[bzoj4779][Usaco2010 Hol]Cowwar 奶牛战争 最大流

1779: [Usaco2010 Hol]Cowwar 奶牛战争

Time Limit: 10 Sec   Memory Limit: 64 MB
[ Submit][ Status][ Discuss]

Description

农场主约翰在编号为1到V (1 <= V <= 1,000)一共V片草地上跟他的邻居农场主汤姆有着一 个激烈的争吵。两个农场主目前正在这些草地上放养他们的奶牛,每片草地要不是空的,要不就 被一只属于农场主约翰或者农场主汤姆的奶牛佔领着。 农场主约翰的耐心已经消磨完了,它希望把汤姆所有的奶牛都打到四脚朝天以解决这场争端。他 当然希望可以抢占先机,并且尽可能多地打翻尽农场主汤姆的奶牛。 一共E (1 <= E <= 5,000)条双向道路连接E对草地。没有两片草地由超过一条道路连接,每 条道路恰好连接2片不同的草地。每条路径由它的两个端点P1_i和P2_i (1 <= P1_i <= V; 1 <= P2_i <= V)描述。 在他的进攻过程中,农场主约翰的每一只奶牛如果需要的话,可以走过一条单独的道路。然后, 如果她愿意,可以对相邻(也就是由一条单独的道路相连的)一片草地发动进攻,也就是把上面 的敌牛打翻。注意她可以先移动再攻击 -- 但是她不能先攻击然后再移动。 每片草地上每个时刻最多可以有一只奶牛。一只奶牛不能移动到一个已经有奶牛在上面的草地 上,尤其是上面的奶牛已经被打翻的时候。当然,如果一个草地已经被空出来了,另外一只奶牛 可以在之后走到这片草地,以取代它的位置。一只被打翻的奶牛不能再次被打翻。 农场主约翰想要了解下面两个问题: * 农场主约翰在这场战役的第一波攻击中,可以打翻农场主汤姆的多少只奶牛。 * 如何指挥他的奶牛来移动和攻击,以在这第一波攻击中,打翻最多的农场主汤姆的奶牛。 求出可以打翻的敌牛的最大数目,并按照上面的规则,构建出一个移动和攻击的命令序列来指挥 他的奶牛以打翻这个数目的敌牛。只要能打翻最多的敌牛,任何一个符合条件的序列都是可以接 受的。 考虑这样一个例子。一共有5片草地,分布在一条线上面,如果有的话,每片草地(经由'--', 见下图)连接它左边和右边相邻的草地(如果有的话)。换句话说,草地1和草地2之间有一条道 路相连,草地2到草地3之间有一条道路相连,等等。农场主汤姆('T')有两只奶牛,分别站在草 地1和草地4上面,农夫约翰('J')有2只奶牛,站在草地3和草地5上面('E'表示空的草地): 1 2 3 4 5 T -- E -- J -- T -- J 在这个情况下,农场主约翰可以把农场主汤姆的两只奶牛都打翻。第一步把草地3上的奶牛移动 到草地2。此时,现在草地上的情况是TJETJ。于是农场主约翰就可以让他两只奶牛都向左进攻。 注意,虽然一开始在草地3上面的牛可以不需移动而向右攻击,但是这样的话最右边的奶牛就无 法展开攻击了。于是唯一的可行解肯定跟上面提供的解法有着相同地移动与攻击,儘管农场主 约翰指挥他的奶牛的具体顺序可能稍微有不同。 如果你正确计算出可以打翻敌牛的最大数目但是没有给出一个命令序列(或者这个序列出错), 你将得到这个测试点的50%的分数。有一个程序会来给你的输出记分。

Input

* 第1行: 两个由空格隔开的整数: V 和 E * 第2行: 一个包含V个字符的字符串(没有空格)。其中第i个字符表示草地i一开始的状况。 'E'表示这片草地是空的;'J'表示这片草地上面有一只奶牛,这只奶牛属于农场主 约翰;'T'表示这片草地属于农场主汤姆。 * 第3到第E+2行: 第i+2行包含两个由空格隔开的整数: P1_i 和 P2_i

Output

* 第1行: 一个单独的整数,表示农场主约翰可以打翻的敌牛的最大数目。

Sample Input

5 4
TEJTJ
1 2
2 3
3 4
4 5

Sample Output

2

HINT


输出细节:

其他可行的输出为:

2
MOVE 3 2
ATTACK 5 4
ATTACK 2 1

或者

2
ATTACK 5 4
MOVE 3 2
ATTACK 2 1

其它的输出祇是改变一下命令的顺序。但是并不是所有的数据都是这样的。

Source

题意:奶牛可以攻击相邻的奶牛,但是被打翻的奶牛不可经过,求最多的奶牛数
拆点限制即可
#include<iostream>
#include<cstring>
#include<cstdio>
#define INF 100000000
using namespace std;
const int N = 105;
int n,m,tot,S,T,last[20005],cur[20005],cnt=1,h[20005],q[2000005],ans,lt[20005],snt,mp[1005][1005];
char s[10005];
struct Edge{
	int to,next,v;
}e[2100005],ee[200005];
void insert( int u, int v, int w ){
	e[++cnt].to = v; e[cnt].next = last[u]; e[cnt].v = w; last[u] = cnt;
	e[++cnt].to = u; e[cnt].next = last[v]; e[cnt].v = 0; last[v] = cnt;
}
void adde( int u, int v ){
	ee[++snt].to = v; ee[snt].next = lt[u]; lt[u] = snt;
	ee[++snt].to = u; ee[snt].next = lt[v]; lt[v] = snt;
}
bool bfs(){
	memset(h,-1,sizeof(h));
	int tail = 1, head = 0;
	q[0] = S; h[0] = S;
	while( tail != head ){
		int now = q[head++];
		for( int i = last[now]; i; i = e[i].next )
			if( h[e[i].to] == -1 && e[i].v ){
				h[e[i].to] = h[now] + 1;
				q[tail++] = e[i].to;
			}
	}
	return h[T] != -1;
}
int dfs( int x, int f ){
	int w,used=0;
	if( x == T ) return f;
	for( int i = cur[x]; i; i = e[i].next )
		if( h[e[i].to] == h[x] + 1 ){
			w = dfs(e[i].to,min(e[i].v,f-used));
			e[i].v -= w; e[i^1].v += w; used += w;
			if( e[i].v ) cur[x] = i; if( f == used ) return f;
		}
	if( !used ) h[x] = -1;
	return used;
}
void dinic(){
	while( bfs() ){
		for( int i = S; i <= T; i++ ) cur[i] = last[i];
		ans += dfs(S,INF);
	}
}
int main(){
	scanf("%d%d", &n, &m);
	scanf("%s", s+1);
	S = 0; T = n*3+1;
	for( int i = 1,u,v; i <= m; i++ ) {
		scanf("%d%d", &u, &v); adde(u,v); mp[u][v] = mp[v][u] = 1;
	}
	for( int i = 1; i <= n; i++ ){
		if( s[i] == 'J' ){
			insert( S, i, 1 );
			insert( i, n+i, 1 );
			insert( n+i, n*2+i, 1 );
            for( int j = 1; j <= n;j++ )
                if( mp[i][j] && s[j] != 'T' ) insert( i, n+j, 1 );
		}
		if( s[i] == 'T' ){
			insert( i, T, 1 );
            for ( int j = 1; j <= n; j++ )
                if ( mp[i][j] && s[j] != 'T' ) insert( n+n+j, i, 1 );
		}
		if( s[i] == 'E' ) insert(n+i,n*2+i,1);
	}
	dinic();
	printf("%d", ans);
	return 0;
}


#include<iostream>
#include<cstring>
#include<cstdio>
#define INF 100000000
using namespace std;
const int N = 105;
int n,m,tot,S,T,last[20005],cur[20005],cnt=1,h[20005],q[2000005],ans,lt[20005],snt,mp[1005][1005];
char s[10005];
struct Edge{
	int to,next,v;
}e[2100005],ee[200005];
void insert( int u, int v, int w ){
	e[++cnt].to = v; e[cnt].next = last[u]; e[cnt].v = w; last[u] = cnt;
	e[++cnt].to = u; e[cnt].next = last[v]; e[cnt].v = 0; last[v] = cnt;
}
void adde( int u, int v ){
	ee[++snt].to = v; ee[snt].next = lt[u]; lt[u] = snt;
	ee[++snt].to = u; ee[snt].next = lt[v]; lt[v] = snt;
}
bool bfs(){
	memset(h,-1,sizeof(h));
	int tail = 1, head = 0;
	q[0] = S; h[0] = S;
	while( tail != head ){
		int now = q[head++];
		for( int i = last[now]; i; i = e[i].next )
			if( h[e[i].to] == -1 && e[i].v ){
				h[e[i].to] = h[now] + 1;
				q[tail++] = e[i].to;
			}
	}
	return h[T] != -1;
}
int dfs( int x, int f ){
	int w,used=0;
	if( x == T ) return f;
	for( int i = cur[x]; i; i = e[i].next )
		if( h[e[i].to] == h[x] + 1 ){
			w = dfs(e[i].to,min(e[i].v,f-used));
			e[i].v -= w; e[i^1].v += w; used += w;
			if( e[i].v ) cur[x] = i; if( f == used ) return f;
		}
	if( !used ) h[x] = -1;
	return used;
}
void dinic(){
	while( bfs() ){
		for( int i = S; i <= T; i++ ) cur[i] = last[i];
		ans += dfs(S,INF);
	}
}
int main(){
	scanf("%d%d", &n, &m);
	scanf("%s", s+1);
	S = 0; T = n*3+1;
	for( int i = 1,u,v; i <= m; i++ ) {
		scanf("%d%d", &u, &v); adde(u,v); mp[u][v] = mp[v][u] = 1;
	}
	for( int i = 1; i <= n; i++ ){
		if( s[i] == 'J' ){
			insert( S, i, 1 );
			insert( i, n+i, 1 );
			insert( n+i, n*2+i, 1 );
            for( int j = 1; j <= n;j++ )
                if( mp[i][j] && s[j] != 'T' ) insert(i,n+j,1);
		}
		if( s[i] == 'T' ){
			insert( i, T, 1 );
            for ( int j = 1; j <= n; j++ )
                if ( mp[i][j] && s[j] != 'T' ) insert(n+n+j,i,1);
		}
		if( s[i] == 'E' ) insert(n+i,n*2+i,1);
	}
	dinic();
	printf("%d", ans);
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值