Tricks Device
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 389 Accepted Submission(s): 100
Problem Description
Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the entrance of the tomb while Dumb Zhang’s at the end of it. The tomb is made up of many chambers, the total number is N. And there are M channels connecting the
chambers. Innocent Wu wants to catch up Dumb Zhang to find out the answers of some questions, however, it’s Dumb Zhang’s intention to keep Innocent Wu in the dark, to do which he has to stop Innocent Wu from getting him. Only via the original shortest ways
from the entrance to the end of the tomb costs the minimum time, and that’s the only chance Innocent Wu can catch Dumb Zhang.
Unfortunately, Dumb Zhang masters the art of becoming invisible(奇门遁甲) and tricks devices of this tomb, he can cut off the connections between chambers by using them. Dumb Zhang wanders how many channels at least he has to cut to stop Innocent Wu. And Innocent Wu wants to know after how many channels at most Dumb Zhang cut off Innocent Wu still has the chance to catch Dumb Zhang.
Unfortunately, Dumb Zhang masters the art of becoming invisible(奇门遁甲) and tricks devices of this tomb, he can cut off the connections between chambers by using them. Dumb Zhang wanders how many channels at least he has to cut to stop Innocent Wu. And Innocent Wu wants to know after how many channels at most Dumb Zhang cut off Innocent Wu still has the chance to catch Dumb Zhang.
Input
There are multiple test cases. Please process till EOF.
For each case,the first line must includes two integers, N(<=2000), M(<=60000). N is the total number of the chambers, M is the total number of the channels.
In the following M lines, every line must includes three numbers, and use ai、bi、li as channel i connecting chamber ai and bi(1<=ai,bi<=n), it costs li(0<li<=100) minute to pass channel i.
The entrance of the tomb is at the chamber one, the end of tomb is at the chamber N.
For each case,the first line must includes two integers, N(<=2000), M(<=60000). N is the total number of the chambers, M is the total number of the channels.
In the following M lines, every line must includes three numbers, and use ai、bi、li as channel i connecting chamber ai and bi(1<=ai,bi<=n), it costs li(0<li<=100) minute to pass channel i.
The entrance of the tomb is at the chamber one, the end of tomb is at the chamber N.
Output
Output two numbers to stand for the answers of Dumb Zhang and Innocent Wu’s questions.
Sample Input
8 9 1 2 2 2 3 2 2 4 1 3 5 3 4 5 4 5 8 1 1 6 2 6 7 5 7 8 1
Sample Output
2 6
Source
Recommend
题意:给一个无向图N个点M条边,每条边都有一个时间花费,Innocent Wu仅仅实用最短的时间去追 Dumb Zhang才干追上。但 Dumb Zhang不想让他追上。他能够断开随意边。问至少要断几条边,得答案1。答案2=最多能让他断多少路使得WU仍能追上zhang。
解题:用SPFA求出从N到全部点的最短路,和到全部点最短路上最少经过的边数numk[],这样能够得到答案2=M-numk[1]。接下来就用最大流来做,关键在找增广流时要加入一个满足到达N点时是最短路。
#include<stdio.h> #include<string.h> #include<queue> #include<vector> #include<algorithm> using namespace std; #define captype int const int MAXN = 2010; //点的总数 const int MAXM = 400010; //边的总数 const int INF = 1<<30; struct EDG{ int to,next; captype cap,flow; int d; } edg[MAXM]; int eid,head[MAXN]; int gap[MAXN]; //每种距离(或可觉得是高度)点的个数 int dis[MAXN]; //每一个点到终点eNode 的最短距离 int cur[MAXN]; //cur[u] 表示从u点出发可流经 cur[u] 号边 int pre[MAXN]; int D[MAXN], vist[MAXN], mindis; void init(){ eid=0; memset(head,-1,sizeof(head)); } //有向边 三个參数。无向边4个參数 void addEdg(int u,int v,int d,captype rc=0){ edg[eid].to=v; edg[eid].next=head[u]; edg[eid].d=d; edg[eid].cap=1; edg[eid].flow=0; head[u]=eid++; edg[eid].to=u; edg[eid].next=head[v]; edg[eid].d=INF; edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++; } captype maxFlow_sap(int sNode,int eNode, int n){//n是包含源点和汇点的总点个数,这个一定要注意 memset(gap,0,sizeof(gap)); memset(dis,0,sizeof(dis)); memcpy(cur,head,sizeof(head)); memset(vist,-1,sizeof(vist)); pre[sNode] = -1; gap[0]=n; captype ans=0; //最大流 vist[sNode]=0; int u=sNode ,i ; while(dis[sNode]<n){ //推断从sNode点有没有流向下一个相邻的点 if(u==eNode){ //找到一条可增流的路 captype Min=INF ; int inser; for( i=pre[u]; i!=-1; i=pre[edg[i^1].to]) //从这条可增流的路找到最多可增的流量Min if(Min>edg[i].cap-edg[i].flow){ Min=edg[i].cap-edg[i].flow; inser=i; } for( i=pre[u]; i!=-1; i=pre[edg[i^1].to]){ edg[i].flow+=Min; edg[i^1].flow-=Min; //可回流的边的流量 } ans+=Min; u=edg[inser^1].to; continue; } bool flag = false; //推断是否能从u点出发可往相邻点流 int v; for( i=cur[u]; i!=-1; i=edg[i].next){ v=edg[i].to; if(edg[i].cap>0&&vist[u]+edg[i].d+D[v]!=mindis)//假设是正流,则必须保证是最短的一条路,假设是逆流。表明v点己是在最短路上 continue; vist[v]=mindis-D[v]; if( edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){ flag=true; cur[u]=pre[v]=i; break; } } if(flag){ u=v; continue; } //假设上面没有找到一个可流的相邻点。则改变出发点u的距离(也可觉得是高度)为相邻可流点的最小距离+1 int Mind= n; for( i=head[u]; i!=-1; i=edg[i].next){ v=edg[i].to; if(edg[i].cap>0&&vist[u]+edg[i].d+D[v]!=mindis) continue; vist[v]=mindis-D[v]; if( edg[i].cap-edg[i].flow>0 && Mind>dis[v]){ Mind=dis[v]; cur[u]=i; } } gap[dis[u]]--; if(gap[dis[u]]==0) return ans; //当dis[u]这样的距离的点没有了,也就不可能从源点出发找到一条增广流路径 //由于汇点到当前点的距离仅仅有一种,那么从源点到汇点必定经过当前点,然而当前点又没能找到可流向的点,那么必定断流 dis[u]=Mind+1;//假设找到一个可流的相邻点,则距离为相邻点距离+1。假设找不到,则为n+1 gap[dis[u]]++; if(u!=sNode) u=edg[pre[u]^1].to; //退一条边 } return ans; } int numk[MAXN]; void spfa(int s,int t,int n){ queue<int>q; int inq[MAXN]={0},i; for( i=1; i<=n; i++) D[i]=INF; D[t]=0; numk[t]=0; q.push(t); while(!q.empty()){ int u=q.front(); q.pop(); inq[u]=0; for( i=head[u]; i!=-1; i=edg[i].next) if(edg[i].d==INF&&D[edg[i].to]>D[u]+edg[i^1].d){ D[edg[i].to]=D[u]+edg[i^1].d; numk[edg[i].to]=numk[u]+1; if(inq[edg[i].to]==0) inq[edg[i].to]=1,q.push(edg[i].to); } else if(edg[i].d==INF&&D[edg[i].to]==D[u]+edg[i^1].d&&numk[edg[i].to]>numk[u]+1) { numk[edg[i].to]=numk[u]+1; if(inq[edg[i].to]==0) inq[edg[i].to]=1,q.push(edg[i].to); } } } int main() { int n,m,u,v,cost; while(scanf("%d%d",&n,&m)>0) { init(); for(int i=1; i<=m; i++) { scanf("%d%d%d",&u,&v,&cost); addEdg(u,v,cost); addEdg(v,u,cost); } spfa(1,n,n); int ans1,ans2; ans2=m-numk[1]; mindis=D[1]; ans1=maxFlow_sap(1,n,n); printf("%d %d ",ans1,ans2); } }