终于把这题过了。。。写了我好久!!!
1.对于此题如果用isap算法的话是有很多细节的。。。首先,在更新图之后你必须每次重新bfs,如果你重用以前的最短路造成的结果就是,更新图后并没有什么卵用,这就是造成我为什么wa这么久的原因,我以为只要改变cap后原图什么都不用变,直接isap,其实你想想就知道如果d[s].value=n那么这个时候就算是你有新的路也就直接完了,你更新后没任何用,对于原图。。。所以就wa了。。。。其实,由于我们每次都bfs,我感觉将会导致速度变的慢一些,所以我觉得适合此题的算法应该直接上dicnic,这样因为每次我们bfs的时候都是考虑了流量的,速度应该是会更快一点,而且更好实现。尽管第一次的时候稍慢,但是图不是很小嘛。。。影响应该不大,但是在每次修改后用dicnic就很有优势了。。。
2.还有你找割的时候就是先找num[i]=0的i然后找d[from]>=i&&d[to]<i的边,而且要注意的是,由于是网络流我们是擅自加了一些反向边的,这些反向边我们是不能考虑在割内的。。。这个点也是操机容易错。。。。。
3.写isap的时候注意 value,num,changee,回退的时候是不是根节点,还有就是如果直接是t是有bug的要修改下。//个人总结。。
//num,value,changee,回退,刚开始的bug。注意这5点
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
struct edgee
{
int from, to;
int cap, realcap;
};
struct dist
{
int fa, rev, value;
};
dist d[500];
edgee edge[50000];
edgee stack[50000];
int top;
vector<int>getcut;
vector<int>change;
int first[500], nextt[50000],num[500],n,e,c,changee[500],edgetot;
void addedge(int from, int to, int cap)
{
edge[edgetot].from = from;
edge[edgetot].to = to;
edge[edgetot].cap = cap;
nextt[edgetot] = first[from];
first[from] = edgetot;
edgetot++;
edge[edgetot].from = to;
edge[edgetot].to = from;
edge[edgetot].cap = 0;
nextt[edgetot] = first[to];
first[to] = edgetot;
edgetot++;
}
void bfs(int t,int judge)
{
queue<int>que; num[0] = 0;
for (int i = 1; i <= n; i++)d[i].value = n,num[i]=0;
d[t].value = 0;
num[0]++;
que.push(t);
while (!que.empty())
{
int temp = que.front();
que.pop();
for (int i = first[temp]; i != -1; i = nextt[i])
{
int to = edge[i].to;
if (d[to].value == n )//一般是不加的&& (edge[i ^ 1].cap || judge)
{
d[to].value = d[temp].value + 1;
num[d[to].value]++;
que.push(to);
}
}
}
}
void augument(int t, int mincost,int s,int kind)
{
for (int i = t; i != s; i = d[i].fa)
{
edge[d[i].rev].cap -= mincost;
edge[d[i].rev ^ 1].cap += mincost;
if (kind)change.push_back(d[i].rev), change.push_back(d[i].rev ^ 1);
}
}
int isap(int s, int t,int kind,int startflow)
{
int temp = s; int allcost = startflow; int mincost = 2100000000;
bfs(t,kind^1);
for (int i = 1; i <= n; i++)changee[i] = first[i];
while (d[s].value <n)
{
if (temp == t)
{
augument(t, mincost, s, kind);
allcost += mincost;
if (allcost >= c)break;//这路如果刚开始s=t的话allcost就是2000000000这个bug一定要注意!!!!!
temp = s;
}
bool isahead = false;
for (int &i = changee[temp]; i != -1; i = nextt[i])
{
int to = edge[i].to;
if (d[to].value == d[temp].value - 1 && edge[i].cap > 0)
{
mincost = min(mincost, edge[i].cap);
d[to].fa = temp; d[to].rev = i;
temp = to; isahead = true;
break;
}
}
if (!isahead)
{
int mindist = n;//这不要开大了!!!否则限免容易越界。
for (int i = first[temp]; i != -1; i = nextt[i])
{
int to = edge[i].to;
if (edge[i].cap > 0 && d[to].value < mindist)
mindist = min(mindist, d[to].value);
}
if (--num[d[temp].value] == 0)break;
d[temp].value = mindist + 1;
num[d[temp].value]++;
changee[temp] = first[temp];
if(temp!=s)temp = d[temp].fa;
}
}
return allcost>=2100000000?0:allcost;//是好多就返回好多。
}
bool flowchange(int s, int t, int c,int startflow,edgee &a)
{
for (int i = 0; i < change.size(); i++)edge[change[i]].cap = edge[change[i]].realcap;
change.clear();
a.cap = c;
int flow=isap(s, t, 1, startflow);
a.cap = a.realcap;
return flow >= c;
}
bool com(edgee a, edgee b)
{
if (a.from < b.from)return true;
if (a.from == b.from)return a.to < b.to;
if (a.from > b.from)return false;
return false;
}
int main()
{
int k=1;
while (scanf("%d%d%d", &n, &e, &c) && (n || e || c))
{
if (n == 1)
{
printf("Case %d: possible\n", k++);//如果只有一个点无论如何都是阔以的,然而最大流那个写法检查不出来
continue;
}
edgetot = 0; top = -1; getcut.clear();
for (int i = 1; i <= n; i++)first[i] = -1;
for (int i = 0; i < e; i++)
{
int a, b,c;
scanf("%d%d%d", &a, &b, &c);
addedge(a, b, c);
}
int test = isap(1, n, 0,0);
if (test >= c)
printf("Case %d: possible\n", k);
else
{
int zero = -1;
for (int i = 0; i < n; i++)
{
if (num[i] == 0)
{
zero = i; break;
}
}
for (int i = 0; i < edgetot; i += 2)//这是加2哦!!!!!避免反向边
{
if (d[edge[i].from].value >= zero&&d[edge[i].to].value < zero)
getcut.push_back(i);
}
for (int i = 0; i < edgetot; i++)edge[i].realcap = edge[i].cap;
for (int i = 0; i < getcut.size(); i++)
{
int isright = flowchange(1, n, c, test, edge[getcut[i]]);
if (isright)stack[++top] = edge[getcut[i]];
}
sort(stack, stack + top + 1, com);
if (top == -1)
printf("Case %d: not possible\n", k);
else
{
printf("Case %d: possible option:", k);
for (int i = 0; i <= top; i++)
{
if (i != top)
printf("(%d,%d),", stack[i].from, stack[i].to);
else
printf("(%d,%d)\n", stack[i].from, stack[i].to);
}
}
}
k++;
}
}
void bfs(int t, int judge)
{
queue<int>que; num[0] = 0;
for (int i = 1; i <= n; i++)d[i].value = n, num[i] = 0;
d[t].value = 0;
num[0]++;
que.push(t);
while (!que.empty())
{
int temp = que.front();
que.pop();
for (int i = first[temp]; i != -1; i = nextt[i])
{
int to = edge[i].to; int tempp =( i % 2 == 0 ? i : i ^ 1);
if (d[to].value == n&&edge[tempp].cap>0)//一般是不加的&& (edge[i ^ 1].cap || judge)
{
num[d[to].value]--;
d[to].value = d[temp].value + 1;
num[d[to].value]++;
que.push(to);
}
}
}
}
如果把bfs这样写的话要比原来快几十ms,233333333333333333不过这已经是isap的极限了我觉得这样的isap一定是比dicnic快的(如果图大的话)
上面这段代码是我现在突然想到修改的地方,原本以为会快很多,结果尼玛打脸!!!!不过至少证明是比原来快的,特别是如果遇到一些特殊数据或者图大一点绝对是快很多的。。。嗯,坐等打脸2333333