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 queconst 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;}