题意:给定一个网络,每条边都有一个容量,问是否存在1到n的流量为c的流。如果存在,输出possible,如果不存在,是否可以通过修改一条这样的边的容量,使得存在这样的流?如果有若干个答案,排序后输出。
题解:求出最大流,如果大于等于c,就存在,否则,算出最小割,如果,把最小割中的流量增加到c,再求最大流,如果此时的最大流满足大于c,保存答案。因为这样写会超时,所以用到白书给的两个优化。
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define pb push_back
using namespace std;
const int maxn = 105,inf = 2e9+10000;
struct Edge{
int from,to,cap,flow;
};
bool cmp(const Edge& a,const Edge& b)
{
return a.from < b.from||(a.from==b.from&&a.to<b.to);
}
struct Dinic{
int n,m,s,t;
vector<Edge>edges;
vector<int>g[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int n)
{
this->n=n;
for(int i=0;i<=n;i++)g[i].clear();
edges.clear();
}
void AddEdge(int from,int to,int cap)
{
edges.push_back((Edge){from,to,cap,0});
edges.push_back((Edge){to,from,0,0});
m=edges.size();
g[from].push_back(m-2);
g[to].push_back(m-1);
}
bool BFS()
{
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=0;i<g[x].size();i++)
{
Edge& e=edges[g[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to]=1;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x,int a)
{
if(x==t||a==0)return a;
int flow=0,f;
for(int& i=cur[x];i<g[x].size();i++)
{
Edge& e=edges[g[x][i]];
if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
{
e.flow+=f;
edges[g[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)break;
}
}
return flow;
}
int Maxflow(int s,int t,int need)
{
this->s=s;
this->t=t;
int flow=0;
while(BFS())
{
memset(cur,0,sizeof(cur));
flow+=DFS(s,inf);
if(flow>=need)return flow;
}
return flow;
}
vector<int> Mincut()
{
vector<int>ans;
for(int i=0;i<edges.size();i++)
{
Edge& e=edges[i];
if(vis[e.from]&&!vis[e.to]&&e.cap>0)
ans.push_back(i);
}
return ans;
}
void Reduce()
{
for(int i=0;i<edges.size();i++)
edges[i].cap-=edges[i].flow;
}
void ClearFlow()
{
for(int i=0;i<edges.size();i++)
edges[i].flow=0;
}
}sol;
int main()
{
int n,m,c,kase = 0;
while(~scanf("%d%d%d",&n,&m,&c)&&n)
{
int u,v,w;
sol.init(n);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
sol.AddEdge(u,v,w);
}
printf("Case %d: ",++kase);
int flow = sol.Maxflow(1,n,inf);
if(flow >= c)puts("possible");
else
{
vector<int> cut = sol.Mincut();
sol.Reduce();
vector<Edge>ans;
for(int i=0;i<cut.size();i++)
{
Edge& e = sol.edges[cut[i]];
int tmp = e.cap;
e.cap = c;
sol.ClearFlow();
if(flow + sol.Maxflow(1,n,c-flow) >= c)ans.pb(e);
e.cap = tmp;
}
if(ans.size() == 0)puts("not possible");
else
{
sort(ans.begin(),ans.end(),cmp);
printf("possible option:(%d,%d)",ans[0].from,ans[0].to);
for(int i=1;i<ans.size();i++)printf(",(%d,%d)",ans[i].from,ans[i].to);
printf("\n");
}
}
}
return 0;
}