BZOJ 1266: [AHOI2006]上学路线route
题目描述
可可和卡卡家住合肥市的东郊,每天上学他们都要转车多次才能到达市区西端的学校。直到有一天他们两人参加了学校的信息学奥林匹克竞赛小组才发现每天上学的乘车路线不一定是最优的。
可可:“很可能我们在上学的路途上浪费了大量的时间,让我们写一个程序来计算上学需要的最少时间吧!”
合肥市一共设有N个公交车站,不妨将它们编号为1…N的自然数,并认为可可和卡卡家住在1号汽车站附近,而他们学校在N号汽车站。市内有M条直达汽车路线,执行第i条路线的公交车往返于站点pi和qi之间,从起点到终点需要花费的时间为ti。(1<=i<=M, 1<=pi, qi<=N)
两个人坐在电脑前,根据上面的信息很快就编程算出了最优的乘车方案。然而可可忽然有了一个鬼点子,他想趁卡卡不备,在卡卡的输入数据中删去一些路线,从而让卡卡的程序得出的答案大于实际的最短时间。而对于每一条路线i事实上都有一个代价ci:删去路线的ci越大卡卡就越容易发现这个玩笑,可可想知道什么样的删除方案可以达到他的目的而让被删除的公交车路线ci之和最小。
[任务]
编写一个程序:
l 从输入文件中读取合肥市公交路线的信息;
l 计算出实际上可可和卡卡上学需要花费的最少时间;
l 帮助可可设计一个方案,删除输入信息中的一些公交路线,使得删除后从家到学校需要的最少时间变大,而被删除路线的ci和最小;
l 向输出文件输出答案。
输入
输入文件中第一行有两个正整数N和M,分别表示合肥市公交车站和公交汽车路线的个数。以下M行,每行(第i行,总第(i+1)行)用四个正整数描述第i条路线:pi, qi, ti,ci;具体含义见上文描述。
输出
输出文件最多有两行。
第一行中仅有一个整数,表示从可可和卡卡家到学校需要的最短时间。
第二行ci之和的最小值。
样例输入
6 7 1 2 1 3 2 6 1 5 1 3 1 1 3 4 1 1 4 6 1 1 5 6 1 2 1 5 1 4
样例输出
2 5
提示
2<=N<=500, 1<=M<=124 750, 1<=ti, ci<=10 000
合肥市的公交网络十分发达,你可以认为任意两个车站间都可以通过直达或转车互相到达,当然如果在你提供的删除方案中,家和学校无法互相到达,那么则认为上学需要的最短为正无穷大:这显然是一个合法的方案。
先用SPFA跑出1到n的最短路,然后把满足最短路的边都选出来重新建图,最后跑一遍最小割,细节在于边有重复,容量要用+=.
具体看代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstdlib> 7 #include<queue> 8 #include<vector> 9 using namespace std; 10 const int M=125855; 11 int gi() 12 { 13 int str=0;char ch=getchar(); 14 while(ch>'9' || ch<'0')ch=getchar(); 15 while(ch>='0' && ch<='9')str=str*10+ch-'0',ch=getchar(); 16 return str; 17 } 18 const int N=505; 19 const int INF=1999999999; 20 int n,m;int q[M*10]; 21 struct Lin 22 { 23 int next,to,dis,ct; 24 }a[M*4]; 25 bool vis[N];int f[N][2]; 26 int num=0;int head[N]; 27 void init(int x,int y,int z,int ff) 28 { 29 a[++num].next=head[x]; 30 a[num].to=y; 31 a[num].dis=z; 32 a[num].ct=ff; 33 head[x]=num; 34 } 35 void spfa(bool t,int sta) 36 { 37 int sum=1,tail=0; 38 vis[sta]=1; 39 q[1]=sta; 40 int x,u; 41 for(int i=1;i<=n;i++)vis[i]=0,f[i][t]=INF; 42 f[sta][t]=0; 43 while(tail!=sum) 44 { 45 x=q[++tail]; 46 for(int i=head[x];i;i=a[i].next) 47 { 48 u=a[i].to; 49 if(f[x][t]+a[i].dis<f[u][t]) 50 { 51 f[u][t]=a[i].dis+f[x][t]; 52 if(!vis[u]) 53 { 54 q[++sum]=u; 55 vis[u]=true; 56 } 57 } 58 } 59 vis[x]=false; 60 } 61 } 62 int flow[N][N]; 63 int dep[N]; 64 bool bfs() 65 { 66 memset(dep,0,sizeof(dep)); 67 int t=0,sum=1; 68 dep[1]=1; 69 q[1]=1; 70 int x; 71 while(t!=sum) 72 { 73 x=q[++t]; 74 for(int i=1;i<=n;i++) 75 { 76 if(dep[i] || flow[x][i]<=0)continue; 77 dep[i]=dep[x]+1; 78 q[++sum]=i; 79 } 80 } 81 if(dep[n]) 82 return true; 83 return false; 84 } 85 86 int dfs(int x,int flows) 87 { 88 if(x==n || !flows)return flows; 89 int sum=0,tmp; 90 for(int i=1;i<=n;i++) 91 { 92 if(flow[x][i]<=0 || dep[i]!=dep[x]+1)continue; 93 tmp=dfs(i,min(flows,flow[x][i])); 94 flow[x][i]-=tmp; 95 flow[i][x]+=tmp; 96 flows-=tmp; 97 sum+=tmp; 98 if(!flows)break; 99 } 100 return sum; 101 } 102 void work() 103 { 104 int cc=0,tot=0; 105 while(bfs()){ 106 cc=0;cc=dfs(1,INF); 107 while(cc)tot+=cc,cc=dfs(1,INF); 108 } 109 printf("%d",tot); 110 } 111 void build() 112 { 113 for(int i=1;i<=n;i++){ 114 for(int j=head[i];j;j=a[j].next){ 115 if(f[n][0]==f[a[j].to][1]+f[i][0]+a[j].dis)flow[i][a[j].to]+=a[j].ct; 116 } 117 } 118 } 119 int main() 120 { 121 n=gi();m=gi(); 122 int x,y,z,ss; 123 for(int i=1;i<=m;i++) 124 { 125 x=gi();y=gi();z=gi();ss=gi(); 126 init(x,y,z,ss);init(y,x,z,ss); 127 } 128 spfa(0,1); 129 printf("%d\n",f[n][0]); 130 spfa(1,n); 131 build(); 132 work(); 133 return 0; 134 }