USTC 1280 / 携程决赛1004 最短路径的代价

来源:互联网 发布:大数据金融行业运用 编辑:程序博客网 时间:2024/06/08 18:54

最短路径的代价

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 32   Accepted Submission(s) : 15

Font: Times New Roman | Verdana | Georgia

Font Size:  

Problem Description

通常情况下找到N个节点、M 条边的无向图中某两点的最短路径很简单。假设每条边都有各自的长度以及删除这条边的代价,那么给出两个点X和Y,删除一些边可以使得X到Y的最短路径增加,求删除边最少的代价。

Input

第一行包含参数N和M,分别表示节点和边的个数(2 ≤N≤ 1000,1 ≤M≤ 11000 )
第二行包含参数X和Y,表示源点和终点( 1 ≤ X,Y ≤ N,X ≠ Y);
剩下M行每行包含4个参数Ui、Vi、Wi和Ci,分别表示节点Ui和Vi之间边的长度Wi以及删除的代价Ci ( 1 ≤ Ui , Vi ≤ N, 0 ≤Wi, Ci ≤1000 );
如果某行N=M=0就表示输入结束。

Output

对于每个用例,按行输出增加X和Y直接最短路径所需要的最小代价。这个代价是所有删除的边的代价之和。

Sample Input

2 31 21 2 2 31 2 2 41 2 3 54 51 41 2 1 12 3 1 13 4 1 11 4 3 22 2 2 34 52 31 2 3 22 4 3 41 3 2 33 4 2 31 4 0 10 0

Sample Output

736

Source

CodingTrip - 携程编程大赛 (决赛)
LINK: http://acm.ustc.edu.cn/ustcoj/problem.php?id=1280
这个比赛好多原题,无论是资格赛还是决赛,不吐槽了。  可惜我没有见过几道啊。
这道题目是说, 给你一个图,从s到t 有最短路,图上的每条边都有长度和 删去的代价。要求删除一些边,使得由s->t的最短路增大。要求删掉的边的代价最小。
解法: 先求s->t的最短路。建立新图,如果dis[u]==dis[v]+ 由v到u的边的长度,则添加边(v,u),边长为删去的代价.
之后就是求一个最小割/最大流,把s,t分开.

#include<cstdio>#include<cstring>#include<algorithm>#include<string>#include<vector>#include<queue>#include<cmath>using namespace std;#define INF 1000000000#define N 1005#define M 100005int n,m,s,t,hh1[N],hh2[N],tot1,tot2;int dis[N],inq[N],vis[N],lev[N];struct node{int u,v,w,c,next;}edge1[2*M],edge2[2*M];void init(){tot1=tot2=0;memset(hh1,-1,sizeof(hh1));memset(hh2,-1,sizeof(hh2));}void add1(int u,int v,int w,int c){edge1[tot1].u=u; edge1[tot1].v=v;edge1[tot1].w=w; edge1[tot1].c=c;edge1[tot1].next=hh1[u]; hh1[u]=tot1++;}void add2(int u,int v,int c){edge2[tot2].u=u; edge2[tot2].v=v;edge2[tot2].w=c; edge2[tot2].next=hh2[u];hh2[u]=tot2++;edge2[tot2].u=v; edge2[tot2].v=u;edge2[tot2].w=0; edge2[tot2].next=hh2[v];hh2[v]=tot2++;}void spfa(){queue<int > Q;Q.push(s);memset(inq,0,sizeof(inq));inq[s]=1;for(int i=0;i<=n;i++) dis[i]=INF;dis[s]=0;while(!Q.empty()){int u=Q.front(); Q.pop();inq[u]--;for(int i=hh1[u];i!=-1;i=edge1[i].next){int v=edge1[i].v;if(dis[v]>dis[u]+edge1[i].w){dis[v]=dis[u]+edge1[i].w;if(!inq[v]){inq[v]=1;Q.push(v);}}}}}void add_(){for(int u=1;u<=n;u++){for(int j=hh1[u];j!=-1;j=edge1[j].next ){int v=edge1[j].v;if(dis[v]==dis[u]+edge1[j].w) add2(u,v,edge1[j].c);}}}int bfs(){queue<int > Q;memset(lev,-1,sizeof(lev));lev[s]=1; Q.push(s);while(!Q.empty()){int u=Q.front(); Q.pop();for(int i=hh2[u];i!=-1; i=edge2[i].next ){int v=edge2[i].v;if(edge2[i].w && lev[v]==-1){lev[v]=lev[u]+1;Q.push(v);}}}return lev[t]!=-1;}int dfs(int u,int flow){if(u==t) return flow;int tmp=flow;for(int i=hh2[u];i!=-1; i=edge2[i].next ){int v=edge2[i].v;if(lev[v]==lev[u]+1){int ad=dfs(v,min(tmp,edge2[i].w));tmp-=ad;edge2[i].w-=ad;edge2[i^1].w+=ad;if(!tmp) break;}}return flow-tmp;}int dinic(){int ret=0;while(bfs()){ret+=dfs(s,INF);}return ret;}int main(){//freopen("in.txt","r",stdin);int time=0;while(scanf("%d%d",&n,&m),n||m){scanf("%d%d",&s,&t);init();int u,v,w,c;for(int i=1;i<=m;i++){scanf("%d%d%d%d",&u,&v,&w,&c);add1(u,v,w,c);add1(v,u,w,c);}spfa();memset(vis,0,sizeof(vis));add_();int ans=dinic();printf("Case %d: %d\n",++time,ans);//printf("%d\n",ans);}    return 0;}


0 0