[最小割+dijkstra]中科大ACM除夕挑战赛A
大致题意:
? ? ?给出一个由n个节点,m条边组成的无向图,每条边都有各自的长度和一个花费值c,意味着删去这条无向边需要的花费。给出两个点s和t,现在要删去一些边使得s到t的最短路增加,求花费最少是多少。
?
大致思路:
? ? 首先,对于一条边(u,v),如果s—>v== s—>u +u—>v我们就可以认为这条边是s到t的最短路上面的一条边。用dijkstra先求出s到所有点的最短距离,然后枚举每条边用上面的方法判定这条边是否在最短路上。如果(u,v)是属于某个最短路的一条边,则在网络图中加上u->v,容量设为删去这条边的花费。接下来对图中的s点到t点求一遍最小割,得到的就是答案。
?
#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;const int nMax=1500;const int mMax=200000;class node{ public: int c,u,v,next;};node edge[mMax];int ne, head[nMax],n;int cur[nMax], ps[nMax], dep[nMax];const int inf=1<<29;void addedge(int u, int v,int c){ ////dinic的加边方法 // cout<<u<<" add "<<v<<" "<<c<<endl; edge[ne].u = u; edge[ne].v = v; edge[ne].c = c; edge[ne].next = head[u]; head[u] = ne ++; edge[ne].u = v; edge[ne].v = u; edge[ne].c = 0; edge[ne].next = head[v]; head[v] = ne ++;}int dinic(int s, int t){ // 网络流dinic算法。 int tr, res = 0; int i, j, k, f, r, top; while(1){ memset(dep, -1, sizeof(dep)); for(f = dep[ps[0]=s] = 0, r = 1; f != r;) for(i = ps[f ++], j = head[i]; j; j = edge[j].next) if(edge[j].c && dep[k=edge[j].v] == -1){ dep[k] = dep[i] + 1; ps[r ++] = k; if(k == t){ f = r; break; } } if(dep[t] == -1) break; memcpy(cur, head, sizeof(cur)); i = s, top = 0; while(1){ if(i == t){ for(tr =inf, k = 0; k < top; k ++) if(edge[ps[k]].c < tr) tr = edge[ps[f=k]].c; for(k = 0; k < top; k ++) { edge[ps[k]].c -= tr; edge[ps[k]^1].c += tr; } i = edge[ps[top=f]].u; res += tr; } for(j = cur[i]; cur[i]; j = cur[i] =edge[cur[i]].next){ if(edge[j].c && dep[i]+1 == dep[edge[j].v]) break; } if(cur[i]){ ps[top ++] = cur[i]; i = edge[cur[i]].v; } else{ if(top == 0) break; dep[i] = -1; i = edge[ps[-- top]].u; } } } return res;}int map[nMax][nMax],co[nMax][nMax],dis[nMax];bool vis[nMax];void dijkstra(int from){ for(int i=0;i<=n;i++)dis[i]=inf; memset(vis,false,sizeof(vis)); vis[from]=true; dis[from]=0; int mine; int now=from; for(int i=1;i<n;i++){ for(int k=1;k<=n;k++) if( map[now][k]!=inf&&dis[now]!=inf&&map[now][k]+dis[now]<dis[k]) dis[k] = dis[now] + map[now][k]; mine=inf; for(int k=1;k<=n;k++) if(mine>dis[k]&&!vis[k]) mine=dis[now=k]; vis[now]=true; } // for(int i=1;i<=n;i++)cout<<dis[i]<<" ";cout<<endl;}void buildmap(int s,int t,int N){ int i,j; for(i=1;i<=N;i++){ if(dis[i]==inf)continue; for(j=1;j<=N;j++){ if(i==j)continue; if(dis[j]==dis[i]+map[i][j])addedge(i,j,co[i][j]); } }}int main(){ int i,j,m,a,b,c,s,t,u,v,cas=0; while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){ cas++; ne=2; memset(head,0,sizeof(head)); scanf("%d%d",&s,&t); for(i=1;i<=n;i++){ for(j=0;j<=n;j++){ map[i][j]=inf; }map[i][i]=0; } while(m--){ scanf("%d%d",&u,&v); scanf("%d%d",&a,&b); if(a>map[u][v])continue; if(a==map[u][v]){ co[u][v]+=b; co[v][u]+=b; continue; } map[u][v]=a; co[v][u]=co[u][v]=b; map[v][u]=map[u][v]; } dijkstra(s); if(dis[t]==inf){ printf("Case %d: %d\n",cas,0); continue; } buildmap(s,t,n); printf("Case %d: %d\n",cas,dinic(s,t)); } return 0;}?