- P5905 【模板】Johnson 全源最短路
- P1144 最短路計數
- P1462 通往奧格瑞瑪的道路
- P1522 [USACO2.4]牛的旅行 Cow Tours
- P1266 速度限制
- P4001 [ICPC-Beijing 2006]狼抓兔子
- P4568 [JLOI2011]飛行路線
- P3238 [HNOI2014]道路堵塞
- P5304 [GXOI/GZOI2019]旅行者
1.P5905 【模板】Johnson 全源最短路
利用一個騷勢能公式讓dij可以跑負權圖
思路是先建一個超級源點跟每個點建一條權爲0的邊
跑spfa,有環就退出
然後重新賦上邊權
e[i].w+=h[u]-h[e[i].v]; h是spfa跑出來到每個點的最短路
原理的話oiwiki上講的很清楚
完整代碼:
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=5005,maxm=10005;
struct edge{
int v,w,nex;
}e[maxm];
struct node{
int dis,id;
bool operator<(const node&a)const
{
return dis>a.dis;
}
node(int d,int x){
dis=d,id=x;
}
};
int head[maxn],vis[maxn],cs[maxn];
int cnt,n,m;
long long h[maxn],dis[maxn];
inline void add(int u,int v,int w){
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
}
bool spfa(int s){
queue<int>q;
memset(h,63,sizeof(h));
h[s]=0,vis[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(h[v]>h[u]+e[i].w){
h[v]=h[u]+e[i].w;
if(!vis[v]){
vis[v]=1;
q.push(v);
cs[v]++;
if(cs[v]==n)return false;
}
}
}
}
return true;
}
inline void dij(int s){
priority_queue<node>q;
for(int i=1;i<=n;i++)
dis[i]=inf;
memset(vis,0,sizeof(vis));
dis[s]=0;
q.push(node(0,s));
while(!q.empty()){
int u=q.top().id;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
if(!vis[v])q.push(node(dis[v],v));
}
}
}
return;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
}
for(int i=1;i<=n;i++){
add(0,i,0);
}
if(!spfa(0)){
cout<<-1<<endl;
return 0;
}
for(int u=1;u<=n;u++)
for(int i=head[u];i;i=e[i].nex)
e[i].w+=h[u]-h[e[i].v];
for(int i=1;i<=n;i++){
dij(i);
long long ans=0;
for(int j=1;j<=n;j++){
if(dis[j]==inf)ans+=j*inf;
else ans+=j*(dis[j]+h[j]-h[i]);
}
cout<<ans<<endl;
}
return 0;
}
2.P1144 最短路計數
給一個無向無權圖,求1到每一點的最短路的條數
bfs+記錄貢獻 無了
如果一個點沒有被訪問過,它的被訪問次序爲前一點的次序+1
if(!vis[t]){
vis[t]=1;
tiao[t]=tiao[x]+1;
q.push(t);
}
如果這個點是距離前一個點最近的點
就加上前一個點的所有路徑數
if(tiao[t]==tiao[x]+1){
cnt[t]=(cnt[t]+cnt[x])%mod;
}
#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,ans;
const int mod=100003;
struct node{
int v,w,tiao;
};
vector<int>a[1000005];
int vis[1000005];
int tiao[1000005],cnt[1000005];
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
void bfs(int x){
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
x=read();
y=read();
a[x].push_back(y);
a[y].push_back(x);
}
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(1);
tiao[1]=0;
vis[1]=1;
cnt[1]=1;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<a[x].size();i++){
int t=a[x][i];
if(!vis[t]){
vis[t]=1;
tiao[t]=tiao[x]+1;
q.push(t);
}
if(tiao[t]==tiao[x]+1){
cnt[t]=(cnt[t]+cnt[x])%mod;
}
}
}
for(int i=1;i<=n;i++){
printf("%d\n",cnt[i]);
}
return 0;
}
3. P1462 通往奧格瑞瑪的道路
在血量限制下,最小費用和
二分最大費用跑dij,超過mid的路不能走,血量夠就可以到達終點
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf=0x3f3f3f3f;
int n,m,b,ans,l,r,dis[10005],vis[10005],minn=9999999,maxx=-9999999;
struct node{
int w,now;
bool operator <(const node&x)const
{
return w>x.w;
}
};
struct edge{
int v,w;
};
vector<edge>p[10005],d;
int c[10005];
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
priority_queue<node>q;
inline int dij(int money){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
dis[i]=inf;
}
dis[1]=0;
q.push((node){0,1});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(c[v]>money)continue;
if(dis[v]>dis[u]+p[u][i].w){
dis[v]=dis[u]+p[u][i].w;
q.push((node){dis[v],v});
}
}
}
if(dis[n]<=b)return 1;
else return 0;
}
bool judge(int x){
if(c[1]>x)return false;
int tt=dij(x);
if(tt==1)return true;
else return false;
}
signed main(){
n=read(),m=read(),b=read();
for(int i=1;i<=n;i++){
c[i]=read();
minn=min(minn,c[i]);
maxx=max(maxx,c[i]);
}
for(int i=1;i<=m;i++){
int x,y,z;
x=read(),y=read(),z=read();
p[x].push_back((edge){y,z});
p[y].push_back((edge){x,z});
}
// sort(c+1,c+1+n);
l=minn;
r=maxx;
while(l<=r){
int mid=(l+r)>>1;
if(judge(mid))r=mid-1,ans++;
else l=mid+1;
}
if(ans==0)cout<<"AFK";
else cout<<l;
return 0;
}
4.P1522 [USACO2.4]牛的旅行 Cow Tours
傻逼題
讀了半天才讀懂題意
求連接各個聯通塊的最短路+聯通塊內距離
數據小,Floyd即可
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int n;
double mp[200][200],dis[200][200];
struct pos{
double x,y;
}a[200];
double ltk[200];
double juli(int i,int j){
return sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
}
char t;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>t;
if(t=='1')dis[i][j]=juli(i,j);
else if(i!=j)dis[i][j]=inf;
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
double mi=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dis[i][j]!=inf){
ltk[i]=max(ltk[i],dis[i][j]);
}
mi=max(mi,ltk[i]);
}
}
double mm=inf;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dis[i][j]==inf){
mm=min(mm,ltk[i]+ltk[j]+juli(i,j));
}
}
}
mm=max(mi,mm);
printf("%.6f",mm);
return 0;
}
5.P1266 速度限制
第一次接觸分層圖最短路
把一維的 dis[i] 換成二維 dis[i][j],i代表到達的點v,j代表速率
跑spfa或dij即可(不卡spfa,用dij保險)
#include<bits/stdc++.h>
using namespace std;
int head[505],cnt;
struct edge{
int u,v,speed,l,nex;
}e[30005];
struct node{
int u,speed;
};
inline void add(int u,int v,int speed,int l){
e[++cnt].v=v;
e[cnt].speed=speed;
e[cnt].l=l;
e[cnt].nex=head[u];
head[u]=cnt;
}
node pre[505][505];
int inque[505][505],n,m,d;
double dis[505][505];
void pri(int u,int speed){
if(pre[u][speed].u!=-1)pri(pre[u][speed].u,pre[u][speed].speed);
printf("%d ",u);
return;
}
void spfa(){
for(int i=0;i<=n;i++){
for(int j=0;j<=505;j++){
dis[i][j]=9e17;
pre[i][j].u=pre[i][j].speed=-1;
}
}
queue<node>q;
q.push((node){0,70});
inque[0][70]=1;
dis[0][70]=0;
while(!q.empty()){
node x=q.front();
q.pop();
int u=x.u;
int uv=x.speed;
inque[u][uv]=0;
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
int l=e[i].l;
int vv;
if(e[i].speed!=0)vv=e[i].speed;
else vv=uv;
if(dis[v][vv]>dis[u][uv]+(double)l/vv){
dis[v][vv]=dis[u][uv]+(double)l/vv;
pre[v][vv].u=u;
pre[v][vv].speed=uv;
if(!inque[v][vv]){
q.push((node){v,vv});
inque[v][vv]=1;
}
}
}
}
}
int main(){
cin>>n>>m>>d;
int u,v,w,l;
for(int i=1;i<=m;i++){
cin>>u>>v>>w>>l;
add(u,v,w,l);
}
spfa();
double mm=9e18;
int mx;
for(int i=1;i<=505;i++){
if(mm>dis[d][i]){
mm=dis[d][i];
mx=i;
}
}
pri(d,mx);
return 0;
}
6.P4001 [ICPC-Beijing 2006]狼抓兔子
這題原意是要我們會對偶圖…
最大流=最小割=對偶圖最短路
所以我就跑了最大流hhh
細心建圖(一開始讀入假了,還過了三個點)
#include<bits/stdc++.h>
using namespace std;
const int inf =0x3f3f3f3f,maxn=1e6+5,maxm=3e6+5;
int cur[maxn],head[maxn],dep[maxn];
int cnt=1,maxflow=0,n,m,s,t;
struct edge{
int v,w,nex;
}e[maxm*2];
inline void add_edge(int u,int v,int w){
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
e[++cnt].v=u;
e[cnt].w=w;
e[cnt].nex=head[v];
head[v]=cnt;
}
bool bfs(){
memset(dep,0,sizeof(dep));
memcpy(cur,head,sizeof(head));
dep[s]=1;
queue<int>q;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i;i=e[i].nex){
int v=e[i].v;
if(!dep[v]&&e[i].w){
dep[v]=dep[u]+1;
q.push(v);
if(v==t)return true;
}
}
}
return false;
}
int dfs(int u,int now){
if(u==t||now==0){
return now;
}
int flow=0,rlow=0;
for(int i=cur[u];i;i=e[i].nex){
int v=e[i].v;
if(e[i].w&&dep[v]==dep[u]+1){
if(rlow=dfs(v,min(now,e[i].w))){
flow+=rlow;
now-=rlow;
e[i].w-=rlow;
e[i^1].w+=rlow;
if(now==0)return flow;
}
}
}
if(!flow)dep[u]=-1;
return flow;
}
int dinic(){
while(bfs()){
maxflow+=dfs(s,inf);
}
return maxflow;
}
int main(){
scanf("%d%d",&n,&m);
int u,v,w;
s=1;
t=n*m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m-1;j++){
scanf("%d",&w);
add_edge((i-1)*m+j,(i-1)*m+j+1,w);
}
}
for(int i=1;i<=n-1;i++){
for(int j=1;j<=m;j++){
scanf("%d",&w);
add_edge((i-1)*m+j,i*m+j,w);
}
}
for(int i=1;i<=n-1;i++){
for(int j=1;j<=m-1;j++){
scanf("%d",&w);
add_edge((i-1)*m+j,i*m+j+1,w);
}
}
// for(int i=1;i<=n*m;i++){
// for(int j=head[i];j;j=e[j].nex){
// printf("%d %d %d\n",i,e[j].v,e[j].w);
// }
// }
printf("%d",dinic());
return 0;
}
7.P4568 [JLOI2011]飛行路線
分層圖最短路
跟之前那題一樣
第二維代表用了幾次免費,跑dij即可
#include<bits/stdc++.h>
using namespace std;
#define maxn 200010
#define maxm 200010
const int inf=0x3f3f3f3f;
inline int read()
{
int x=0,k=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')k=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*k;
}
struct edge{
int v,w;
}e[maxm];
int cnt,n,m,s,vis[maxn][15],dis[maxn][15],k,t;
vector<edge>p[100005];
struct node{
int w,now,cs;
bool operator <(const node&x)const
{
return w>x.w;
}
};
priority_queue<node>q;
inline void dij(int s){
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s][0]=0;
q.push((node){0,s,0});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
int cs=x.cs;
if(vis[u][cs])continue;
vis[u][cs]=1;
for(int i=0;i<p[u].size();i++){
int v=p[u][i].v;
if(cs<k&&dis[v][cs+1]>dis[u][cs]){
dis[v][cs+1]=dis[u][cs];
q.push((node){dis[v][cs+1],v,cs+1});
}
if(dis[v][cs]>dis[u][cs]+p[u][i].w){
dis[v][cs]=dis[u][cs]+p[u][i].w;
q.push((node){dis[v][cs],v,cs});
}
}
}
}
signed main(){
n=read(),m=read(),k=read();
s=read()+1,t=read()+1;
for(int i=1,x,y,z;i<=m;i++){
x=read()+1,y=read()+1,z=read();
p[x].push_back((edge){y,z});
p[y].push_back((edge){x,z});
}
dij(s);
int ans=0x7f7f7f7f;
for(int i=0;i<=k;i++){
ans=min(ans,dis[t][i]);
}
cout<<ans;
return 0;
}
8.P3238 [HNOI2014]道路堵塞
黑題,咕咕咕待補
9.P5304 [GXOI/GZOI2019]旅行者
黑題,咕咕咕待補