uva11248isap模板(超级版)

终于把这题过了。。。写了我好久!!!

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值