USACO 2009 Mar Earthquake Damage 2 地震破坏

这道题其实就是网络流,难在建图。

应该可以看出,这道题就是求一个最小割。

超级源点和超级汇点这个不在赘述,主要的一个就是要把所有点都拆成流入点和流出点,并且权值设为1。

而对于与超级源点相连的点,则再加一条流量为正无穷的边,不然在用dinic算法算的时候会直接选择把这几个点切断。

#include<cstdio>
#include<cstring>

const int MAXP=3000*2;
const int MAXC=20000;
const int MAX=(MAXC*3+MAXP*3+10)*2;
const int INF=30000;

int p,c,n;
int s,t,k,first[MAXP+3],next[MAX],head[MAX],tail[MAX],f[MAX];
int q[MAXP+3],qhead,qtail;
int d[MAXP+3];
int ans;

inline void open_file(void)
{
	freopen("damage2.in","r",stdin);
	freopen("damage2.out","w",stdout);
}

inline int getint(void)
{
	int a;
	scanf("%d",&a);
	return a;
}

inline void addedge(int u,int v,int w,int k)
{
	next[k]=first[u];
	first[u]=k;
	head[k]=u;
	tail[k]=v;
	f[k]=w;
}

inline void init(void)
{
	p=getint();
	c=getint();
	n=getint();
	s=p+p+1;
	t=1;
	k+=2;
	addedge(1,1+p,INF,k);
	addedge(1+p,1,INF,k^1);
	for(int i=2;i<=p;i++)
	{
		k+=2;
		addedge(i,i+p,1,k);
		addedge(i+p,i,0,k^1);
	}
	for(int i=1;i<=c;i++)
	{
		int a,b;
		a=getint();
		b=getint();
		if(a==b)
			continue;
		k+=2;
		addedge(a+p,b,INF,k);
		addedge(b,a+p,0,k^1);
		k+=2;
		addedge(b+p,a,INF,k);
		addedge(a,b+p,0,k^1);
	}
	for(int i=1;i<=n;i++)
	{
		int r=getint();
		k+=2;
		addedge(s,r,INF,k);
		addedge(r,s,0,k^1);
		k+=2;
		addedge(r,r+p,INF,k);
		addedge(r+p,r,INF,k^1);
	}
}

inline bool bfs(void)
{
	qhead=0;
	qtail=0;
	memset(d,0,sizeof(d));
	d[t]=1;
	q[qtail++]=t;
	while(qhead<qtail)
	{
		int u=q[qhead++];
		for(int e=first[u];e;e=next[e])
		{
			int v=tail[e];
			if(!d[v]&&f[e^1])
			{
				q[qtail++]=v;
				d[v]=d[u]+1;
			}
		}
	}
	return d[s];
}

int dfs(int u,int b)
{
	if(u==t)
		return b;
	int r=0,tmp=0;
	for(int e=first[u];e;e=next[e])
	{
		int v=tail[e];
		if(d[v]<d[u]&&f[e])
		{
			tmp=dfs(v,(b-r)<f[e]?(b-r):f[e]);
			f[e]-=tmp;
			f[e^1]+=tmp;
			r+=tmp;
		}
	}
	return r;
}

inline void solve(void)
{
	while(bfs())
	{
		ans+=dfs(s,INF);
	}
}

inline void output(void)
{
	printf("%d\n",ans);
}

inline void close_file(void)
{
	fclose(stdin);
	fclose(stdout);
}

int main()
{
	open_file();
	init();
	solve();
	output();
	close_file();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值