http://acm.ustc.edu.cn/ustcoj/problem.php?id=1280
这题是中国科大“百分点科技杯"ACM除夕挑战赛 的题目,当时做不出,后来想了一下,TLE1次,wa一次就过了
这题去掉最小费用和的边使得最短路变长,方法是先求一次最短路,然后建新图,图中存在的边当且仅当(u,v) dis[u]+w(u,v)=dis[v],题目就变成求切掉最小的边,切完后最短路必然变大,然后最小割=最大流就可做了,具体实现上就要使得if(dis[u] + e[i].w != dis[v]) e[i].c = 0;把容量变为0就等于切断了边,最短路套spfa模板,网络流套sap模板
Code:
#define inf 1<<30 #define N 1004 #define sta que const int INF = (1<<30); struct edge{ int u,v,w,c; int next;//同一起点的下一条边存储在edge数组中的位置(理解了这个静态邻接表就可以了) }e[N*25]; int head[N];//以该点为起点的第一条边存储在e数组中的位置 int dis[N];//记录与源点距离 bool vis[N];//记录顶点是否在队列中,SPFA算法可以入队列多次 int cnt[N];//记录顶点入队列次数 int ecnt; int n,m; void init(){ ecnt = 0; memset(head,-1,sizeof(head)); } void add(int u,int v,int w,int cost){ e[ecnt].u = u; e[ecnt].v = v; e[ecnt].w = w; e[ecnt].c = cost; e[ecnt].next = head[u]; head[u] = ecnt++;//位置更新 ///////////////////////////// e[ecnt].u = v; e[ecnt].v = u; e[ecnt].w = w; e[ecnt].c = cost; e[ecnt].next = head[v]; head[v] = ecnt++; } bool SPFA(int s){//s是源点编号 queue<int> qq; int i; for(i=1;i<=n;++i){ dis[i] = INF; //将除源点以外的其余点的距离设置为无穷大 vis[i] = 0; cnt[i] = 0; } dis[s]=0; //源点的距离为0 vis[s] = 1; cnt[s]++; //源点的入队列次数增加 qq.push(s); int u,v; while(!qq.empty()){ u = qq.front(); qq.pop(); vis[u] = 0; for(i=head[u];i!=-1;i = e[i].next){ v = e[i].v; int cost = e[i].w; if(dis[v] > cost+dis[u]){ dis[v] = cost+dis[u]; if(!vis[v]){ vis[v] = 1; qq.push(v); cnt[v]++; if(cnt[v] >= n)return false; } } } } return true; } int h[N]; int gap[N]; int source,sink; inline int dfs(int pos,int cost){ if (pos==sink){ return cost; } int j,minh=n-1,lv=cost,d; for (j=head[pos];j!=-1;j=e[j].next){ int v=e[j].v,val=e[j].c; if(val>0){ if (h[v]+1==h[pos]){ if (lv<e[j].c) d=lv; else d=e[j].c; d=dfs(v,d); e[j].c-=d; e[j^1].c+=d; lv-=d; if (h[source]>=n) return cost-lv; if (lv==0) break; } if (h[v]<minh) minh=h[v]; } } if (lv==cost){ --gap[h[pos]]; if (gap[h[pos]]==0) h[source]=n; h[pos]=minh+1; ++gap[h[pos]]; } return cost-lv; } int sap(int st,int ed){ source=st; sink=ed; int ans=0; memset(gap,0,sizeof(gap)); memset(h,0,sizeof(h)); gap[st]=n; while (h[st]<n){ ans+=dfs(st,INT_MAX); } return ans; } int main(){ int s,t; int ca=1; while(scanf("%d%d",&n,&m) && (n+m)){ int i,j; scanf("%d%d",&s,&t); init(); for(i=0;i<m;i++){ int u,v,w,c; scanf("%d%d%d%d",&u,&v,&w,&c); add(u,v,w,c); } SPFA(s);//cout<<ecnt<<endl; for(i=0;i<ecnt;i+=2){ int u = e[i].u; int v = e[i].v; //if(u==1 && v==4){e[i].c=0;e[i+1].c=1;continue;} if(dis[u] + e[i].w != dis[v]){ e[i].c = 0; } if(dis[v] + e[i].w != dis[u]){ e[i+1].c=0; } } //for(i=0;i<ecnt;i++)cout<<e[i].u<<" "<<e[i].v<<" "<<e[i].c<<endl; printf("Case %d: %d\n",ca++,sap(s,t)); } return 0; }