题意:
题意:FJ有N块地,这些地之间有P条双向路,每条路的都有固定的长度l。现在要你找出从第1块地到第n块地的T条不同路径,每条路径上的路不能与先前的路径重复,问这些路径中的最长路的最小是多少。
思路:二分答案+网络流判定。
二分枚举最大边权,重新建图,只保存权不超过最大边权的边。即如果边的长度小于等于我们规定的最大边权 则添加这条边 权值为1, 否则标记为0
然后在网络中起点终点间的容量是原图中的路径数,判断最大流是否>=T
这里要注意的是,本题给的双向边,所以在添加反向弧时,容量应该等于正向弧。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 205;
const int INF = 0x3f3f3f3f;
struct Edge
{
int from,to,next,w;
}edge[2*maxn*maxn],E[maxn*maxn];
int n,m,cnt,head[maxn];
int level[maxn];
void addedge(int u,int v,int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
swap(u,v);
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void build(int limit)
{
cnt = 0;
memset(head,-1,sizeof(head));
for(int i = 1; i <= m; i++)
if(E[i].w <= limit)
addedge(E[i].from,E[i].to,1);
}
int BFS(int src,int des){
queue<int> q;
memset(level,0,sizeof(level));
level[src]=1;
q.push(src);
while(!q.empty()){
int u = q.front();
q.pop();
if(u==des) return 1;
for(int k = head[u];k!=-1;k=edge[k].next){
int v = edge[k].to,w=edge[k].w;
if(level[v]==0&&w!=0){
level[v]=level[u]+1;
q.push(v);
}
}
}
return -1;
}
int dfs(int u,int des,int increaseRoad){
if(u==des) return increaseRoad;
int ret=0;
for(int k=head[u];k!=-1;k=edge[k].next){
int v = edge[k].to, w = edge[k].w;
if(level[v] == level[u] + 1 && w != 0){
int MIN = min(increaseRoad-ret,w);
w = dfs(v,des,MIN);
if(w > 0)
{
edge[k].w -=w;
edge[k^1].w+=w;
ret+=w;
if(ret==increaseRoad) return ret;
}
else level[v] = -1;
}
}
return ret;
}
int Dinic(int src,int des){
int ans = 0;
while(BFS(src,des)!=-1) ans+=dfs(src,des,INF);
return ans;
}
int main()
{
int t;
while(scanf("%d%d%d",&n,&m,&t)!=EOF)
{
for(int i = 1; i <= m; i++)
scanf("%d%d%d",&E[i].from,&E[i].to,&E[i].w);
int l = 1, r = 1000000, mid,ans;
while(l <= r)
{
mid = (l + r) >> 1;
build(mid);
int tmp = Dinic(1,n);
if(tmp >= t)
{
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
printf("%d\n",ans);
}
return 0;
}