【求出最大流后,给一条边扩容后,希望最大流能提升至某一指定值】的若干优化:
1.只扩最小割的边: 错误(即使最小割唯一)
2.只扩flow==cap的边:正确
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#define pb push_back
#define mp make_pair
#define eps 1e-9
#define zero(x) (fabs(x)<eps)
#define pi acos(-1.0)
#define f1 first
#define f2 second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define initial 1,n,1
const int inf=2000000010;
//const long long INF=1LL<<50;
using namespace std;
typedef long long LL;
typedef pair <int, int> PII;
template<typename X> inline bool minimize(X&p,X q){if(p<=q)return 0;p=q;return 1;}
template<typename X> inline bool maximize(X&p,X q){if(p>=q)return 0;p=q;return 1;}
const int MAXN=111;
int n,m,cc,yy;
int b[10005][3];
struct ISAP
{ struct Edge
{
int from,to,cap,flow;
Edge(){}
Edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d){}
bool operator<(const Edge &oth)const
{
if (from!=oth.from) return from<oth.from;
return to<oth.to;
}
};
int n,m,s,t;//结点数,边数(含反向弧),源点,汇点
vector<Edge> edges,pp,anss;//边表,edges[e]&edges[e^1]互为反向弧
vector<int> G[MAXN];//邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[MAXN];//BFS使用
int d[MAXN];//从起点到i的距离
int cur[MAXN];//当前弧下标
int p[MAXN];//可增广路上的上一条弧
int num[MAXN];//距离标号计数
void AddEdge(int from,int to,int cap)//重边不影响
{ //printf("%d %d %d\n",from,to,cap);
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));//容量为0,表示反向弧
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
void init(int n)
{
this->n=n;
for(int i=0;i<n;++i) G[i].clear();
edges.clear();
}
void BFS()//反向
{ for (int i=0;i<n;i++)
d[i]=n+10; //!!!
memset(vis,0,sizeof(vis));
queue<int> Q;
Q.push(t);
d[t]=0;
vis[t]=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]^1];
if(!vis[e.from]&&e.cap>e.flow)
{
vis[e.from]=1;
d[e.from]=d[x]+1;
Q.push(e.from);
}
}
}
}
int Augment()
{
int x=t,a=inf;
while(x!=s)
{
Edge& e=edges[p[x]];
a=min(a,e.cap-e.flow);
x=edges[p[x]].from;
}
x=t;
while(x!=s)
{
edges[p[x]].flow+=a;
edges[p[x]^1].flow-=a;
x=edges[p[x]].from;
}
return a;
}
int Maxflow(int s,int t)//结点数
{
this->s=s,this->t=t;
int flow=0;
BFS();
memset(num,0,sizeof(num));
for(int i=0;i<n;++i) if (d[i]!=n+10)++num[d[i]];//!!!
int x=s;
memset(cur,0,sizeof(cur));
while(d[s]<n)
{
if(x==t)
{
flow+=Augment();
if (flow+yy>=cc) return flow;
x=s;
}
int ok=0;
for(int i=cur[x];i<G[x].size();++i)
{
Edge& e=edges[G[x][i]];
if(e.cap>e.flow&&d[x]==d[e.to]+1)//Advance
{
ok=1;
p[e.to]=G[x][i];
cur[x]=i;
x=e.to;
break;
}
}
if(!ok)//Retreat
{
int m=n-1;
for(int i=0;i<G[x].size();++i)
{
Edge& e=edges[G[x][i]];
if(e.cap>e.flow) m=min(m,d[e.to]);
}
if(--num[d[x]]==0) break;//gap优化
num[d[x]=m+1]++;
cur[x]=0;
if(x!=s) x=edges[p[x]].from;
}
}
return flow;
}
void dfs1(int x)
{ vis[x]=1;
for(int i=0;i<G[x].size();++i)
{
Edge& e=edges[G[x][i]];
if(e.flow<e.cap&&!vis[e.to]) dfs1(e.to);
}
}
void dfs2(int x)
{ vis2[x]=1;
for(int i=0;i<g[x].size();++i)
if(!vis2[g[x][i]]) dfs2(g[x][i]);
}
vector<int> g[MAXN];
bool vis2[MAXN];
void solve()
{ for (int i=0;i<n;i++) g[i].clear();
for (int i=0;i<edges.size();i++)
if (edges[i].flow<edges[i].cap)
g[edges[i].to].push_back(edges[i].from);
memset(vis,0,sizeof(vis));
memset(vis2,0,sizeof(vis2));
dfs1(s);
dfs2(t);
pp.clear(); anss.clear();
for (int i=0;i<edges.size();i++)pp.pb(edges[i]);
for (int i=0;i<pp.size();i+=2)
if (pp[i].flow==pp[i].cap)
{
edges.clear();
for (int ii=0;ii<pp.size();ii++)edges.pb(pp[ii]);
edges[i].cap=cc;
int tmp=Maxflow(s,t);
if (tmp+yy>=cc) anss.pb(edges[i]);
}
}
}it;
void doit()
{
it.init(n);
for (int i=1;i<=m;i++)
{scanf("%d%d%d",&b[i][0],&b[i][1],&b[i][2]);
b[i][0]--;b[i][1]--;
it.AddEdge(b[i][0],b[i][1],b[i][2]);
}
yy=0;
yy=it.Maxflow(0,n-1);
if (yy>=cc){printf("possible\n");return;}
it.solve();
sort(it.anss.begin(),it.anss.end());
if (it.anss.size()==0) {printf("not possible\n");return;}
printf("possible option:");
bool have=0;
for (int i=0;i<it.anss.size();i++)
{ if (have) printf(",");
printf("(%d,%d)",it.anss[i].from+1,it.anss[i].to+1);
have=1;
}
printf("\n");
}
int main()
{ int id=0;
//freopen("in.txt","r",stdin);
while (scanf("%d%d%d",&n,&m,&cc),n||m||cc)
{printf("Case %d: ",++id);
doit();
}
}
/*
4 4 5
1 2 5
1 3 5
2 4 5
3 4 5
4 4 5
3 4 1
1 2 1
1 3 5
2 4 5
4 4 5
1 2 1
1 3 1
2 4 1
3 4 1
0 0 0
*/