Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 8189 | Accepted: 2485 |
Description
Input
Output
Sample Input
7 9 2 1 2 2 2 3 5 3 7 5 1 4 1 4 3 1 4 5 7 5 7 1 1 6 3 6 7 3
Sample Output
5
Hint
Source
题意:FJ有N块地,这些地之间有P条双向路,每条路的都有固定的长度l。现在要你找出从第1块地到第n块地的T条不同路径,每条路径上的路不能与先前的路径重复,问这些路径中的最长路的最小是多少。
思路:二分答案+网络流判定。
#include <stdio.h> #include <string.h> #define VM 222 #define EM 81111*2 #define inf 0x3f3f3f3f struct Edge { int frm,to,cap,next; }edge[EM]; int head[VM],dep[VM],ep,n; //dep为点的层次 void addedge (int cu,int cv,int cw) //第一条边下标必须为偶数 { edge[ep].frm = cu; edge[ep].to = cv; edge[ep].cap = cw; edge[ep].next = head[cu]; head[cu] = ep; ep ++; edge[ep].frm = cv; edge[ep].to = cu; edge[ep].cap = cw; edge[ep].next = head[cv]; head[cv] = ep; ep ++; } int BFS (int src,int des) //求出层次图 { int que[VM],i,front = 0,rear = 0; memset (dep,-1,sizeof(dep)); que[rear++] = src; dep[src] = 0; while (front != rear) { int u = que[front++]; front = front%VM; for (i = head[u];i != -1;i = edge[i].next) { int v = edge[i].to; if (edge[i].cap > 0&&dep[v] == -1) //容量大于0&&未在dep中 { dep[v] = dep[u] + 1; //建立层次图 que[rear ++] = v; rear = rear % VM; if (v == des) //找到汇点 返回 return 1; } } } return 0; } int dinic (int src,int des) { int i,res = 0,top; int stack[VM]; //stack为栈,存储当前增广路 int cur[VM]; //存储当前点的后继 跟head是一样的 while (BFS(src,des)) //if BFS找到增广路 { memcpy (cur,head,sizeof (head)); int u = src; //u为当前结点 top = 0; while (1) { if (u == des) //增广路已全部进栈 { int min = inf,loc ; for (i = 0;i < top;i ++) //找最小的增广跟并loc记录其在stack中位置 if (min > edge[stack[i]].cap) //以便退回该边继续DFS { min = edge[stack[i]].cap; loc = i; } for (i = 0;i < top;i ++) //偶数^1 相当加1 奇数^1相当减1 当正向边 = 0&&路径不合适时,正加负减 { //偶数是正向边,奇数是负向边,边从0开始 edge[stack[i]].cap -= min; edge[stack[i]^1].cap += min; } //将增广路中的所有边修改 res += min; top = loc; u = edge[stack[top]].frm; //当前结点修改为最小边的起点 } for (i = cur[u];i != -1;cur[u] = i = edge[i].next) //找到当前结点对应的下一条边 if (edge[i].cap != 0&&dep[u] + 1 == dep[edge[i].to])//不满足条件时,修改cur值(去掉不合适的占)eg:1-->2 1-->3 1-->4 有边 但只有 break; // 1-->4 这条边满足条件 就把1到2、3的边给去掉 if (cur[u] != -1) //当前结点的下一条边存在 { stack[top ++] = cur[u]; //把该边放入栈中 u = edge[cur[u]].to; //再从下个点开始找 } else { if (top == 0) //当前结点无未遍历的下一条边且栈空,DFS找不到下一条增广路 break; dep[u] = -1; //当前结点不在增广路中,剔除该点 u = edge[stack[--top]].frm; //退栈 回朔,继续查找 } } } return res; } struct IN { int x,y,c; }q[EM]; int sovle(int mid,int src,int des,int m,int k) { ep = 0; memset (head,-1,sizeof(head)); for(int i=0;i<m;i++) { if(q[i].c<=mid) addedge(q[i].x,q[i].y,1); // addedge(q[i].y,q[i].x,1); } if(dinic (src,des)>=k) return 1; return 0; } int main () { int n,m,v1,v2,w,k,i; int src,des; while (scanf ("%d %d %d",&n,&m,&k)!=EOF) { // ep = 0; src=1;des=n; // memset (head,-1,sizeof(head)); for(i=0;i<m;i++) { scanf("%d %d %d",&v1,&v2,&w); q[i].x=v1;q[i].y=v2;q[i].c=w; } int left,right,mid,ans=-1; left=0;right=1000000; while(left<=right) { mid=(left+right)/2; if(sovle(mid,src,des,m,k)) { ans=mid; right=mid-1; } else left=mid+1; } printf ("%d\n",ans); } return 0; }
#include <stdio.h> #include <string.h> #define VM 222 #define EM 81111*2 #define inf 0x3f3f3f3f struct Edge { int to, frm, nxt, cap; }edge[EM]; int head[VM], ep, n, src, des; int dep[VM], gap[VM]; //gap[x]=y:说明残留网络中dep[i]=x的个数为y void addedge(int u, int v, int c) { edge[ep].frm = u; edge[ep].to = v; edge[ep].cap = c; edge[ep].nxt = head[u]; head[u] = ep++; edge[ep].frm = v; edge[ep].to = u; edge[ep].cap = 0; edge[ep].nxt = head[v]; head[v] = ep++; } void BFS() { memset(dep, -1, sizeof(dep)); memset(gap, 0, sizeof(gap)); gap[0] = 1; //说明此时有1个dep[i] = 0 int que[VM], front = 0, rear = 0; dep[des] = 0; que[rear++] = des; int u, v; while (front != rear) { u = que[front++]; front = front%VM; for (int i=head[u]; i!=-1; i=edge[i].nxt) { v = edge[i].to; if (edge[i].cap != 0 || dep[v] != -1) continue; que[rear++] = v; rear = rear % VM; ++gap[dep[v] = dep[u] + 1]; //求出各层次的数量 } } } int Sap() { int res = 0; BFS(); int cur[VM]; int stack[VM], top = 0; memcpy(cur, head, sizeof(head)); int u = src, i; while (dep[src] < n) { if (u == des) { int temp = inf, inser = n; for (i=0; i!=top; ++i) if (temp > edge[stack[i]].cap) { temp = edge[stack[i]].cap; inser = i; } for (i=0; i!=top; ++i) { edge[stack[i]].cap -= temp; edge[stack[i]^1].cap += temp; } res += temp; top = inser; u = edge[stack[top]].frm; } if (dep[u] != 0 && gap[dep[u] -1] == 0)//出现断层,无增广路 break; for (i = cur[u]; i != -1; i = edge[i].nxt)//遍历与u相连的未遍历结点 if (dep[edge[i].to] != -1) if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1) //层序关系, 找到允许 break; if (i != -1)//找到允许弧 { cur[u] = i; stack[top++] = i;//加入路径栈 u = edge[i].to;//查找下一个结点 } else //无允许的路径,修改标号 当前点的标号比与之相连的点中最小的多1 { int min = n; for (i = head[u]; i != -1; i = edge[i].nxt) //找到与u相连的v中dep[v]最小的点 { if (edge[i].cap == 0) continue; if (min > dep[edge[i].to]) { min = dep[edge[i].to]; cur[u] = i; //最小标号就是最新的允许弧 } } --gap[dep[u]]; //dep[u] 的个数变化了 所以修改gap ++gap[dep[u] = min + 1]; //将dep[u]设为min(dep[v]) + 1, 同时修改相应的gap[] if (u != src) //该点非源点&&以u开始的允许弧不存在,退点 u = edge[stack[--top]].frm; } } return res; } struct IN { int x,y,c; }q[EM]; int sovle(int mid,int m,int k) { //printf("jin\n"); ep = 0; memset (head,-1,sizeof(head)); for(int i=0;i<m;i++) { if(q[i].c<=mid) { addedge(q[i].x,q[i].y,1); addedge(q[i].y,q[i].x,1);//不知道为什么 sap需要添加2次 相反边 } } if(Sap()>=k) return 1; return 0; } int main () { int m,v1,v2,w,k,i; while (scanf ("%d %d %d",&n,&m,&k)!=EOF) { src=1;des=n; for(i=0;i<m;i++) { scanf("%d %d %d",&v1,&v2,&w); q[i].x=v1;q[i].y=v2;q[i].c=w; } int left,right,mid,ans=-1; left=0;right=1000000; while(left<=right) { mid=(left+right)/2; if(sovle(mid,m,k)) { ans=mid; right=mid-1; } else left=mid+1; } printf ("%d\n",ans); } return 0; }