1. 程式人生 > >CDQZ多校集訓題目--盛夏

CDQZ多校集訓題目--盛夏

題意:

給一個有向無環帶權圖,每條路徑上最多隻能割一條邊,最後使1到n無路徑,問最小割邊邊權和是多少。

題意很清楚,但是這道題的題解其實是隻適用於很少的情況的

我們考慮的做法是網路流最小割

對於所有邊的反向邊,流量均為inf

那麼如果具體分析原因其實是這條路徑割上游,那條路徑割下游,然而可以走這條路徑的上游和那條路徑的下游,如何避免?

考慮到那條路徑的上游和這條路徑的下游是沒有割的,中間的邊如果可以反著走那麼就可以很好的避免這種情況的發生

所以如果反向邊是inf就可以很好的解決這個問題了

但是這樣子想未必太過美好了一點,例如:

如果在網路流的圖中有一條邊是反向建的,那麼正向的流量就是inf,導致答案與正確答案不符

無論如何,這道題的思路還是很好的,下貼程式碼

#include<bits/stdc++.h>
using namespace std;
const int inf=0x7fffffff;
int tot=1,w[2005],remain[2005],to[2005],nxt[2005];
int head[305],depth[305],hh[305];
int n,m,shu1,shu2,shu3,ans;
queue <int> que;
int minn(int x,int y)
{
	if(x<y) return x;
	return y;
}
void add(int x,int y,int z)
{
	to[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
	remain[tot]=z;
}
bool bfs()
{
	que.push(1);
	memset(depth,0,sizeof(depth));
	depth[1]=1;
	while(!que.empty())
	{
		int x=que.front();
		que.pop();
		for(int i=head[x];i;i=nxt[i])
		{
			int y=to[i];
			if(!remain[i]||depth[y]) continue;
			depth[y]=depth[x]+1;
			que.push(y);
		}
	}
	return depth[n];
}
int dfs(int x,int delta)
{
	if(x==n) return delta;
	int sum=0;
	for(int &i=hh[x];i&&delta;i=nxt[i])
	{
		int y=to[i];
		if(depth[y]!=depth[x]+1||!remain[i]) continue;
		int flow=minn(remain[i],dfs(y,delta));
		remain[i]-=flow;
		remain[i^1]+=flow;
		sum+=flow;
		delta-=flow;
	}
	return sum;
}
int main()
{
 	freopen("mer.in","r",stdin);
	freopen("mer.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&shu1,&shu2,&shu3);
		add(shu1,shu2,shu3);
		add(shu2,shu1,inf/3);
	}
	while(bfs())
	{
		for(int i=1;i<=n;i++)
		hh[i]=head[i];
		ans+=dfs(1,inf);
	}
	cout<<ans;
	return 0;
}