[Codeforces Gym] 100162A Box Game 博弈+二分图匹配

第一次做交互题,真是留下了心理阴影

先说题目,转化一下模型大概是一个n维棋盘博弈,每次只能移动到坐标相邻的点,已经访问过的点不能重复访问

先求先手必胜还是必败,然后和计算机交互

一道简化很多很多很多的题目:

http://www.lydsy.com/JudgeOnline/problem.php?id=2463

结论:

将初始点拿掉以后,对棋盘黑白染色,若与初始点颜色相反的点个数 >  与初始点颜色相同的个数,则先手必胜,否则先手必败。

至于方案:显然对手所处在的颜色个数小于等于我所在的点颜色的个数,对于每个对手点匹配一个下一个点,每次交互的时候顺着匹配边走就可以了。

注意:

1、dinic能过

2、把结论仔细理解透彻以后再开始写,否则后果不堪设想。

3、map会爆空间

我想是时候去学学匈牙利算法了


#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>

#define N 100050
#define W 16
#define INF (1<<29)

using namespace std;
int n,siz,cnt,S,T,g[2],stdpos;
int vis[N],h[N],c[N],pp[N],ban[N];
int fc[N],cur[N];
bool ans;

struct Node{ int x[W];}w,p,id;
int v(Node p) {
	int s=0 , t=1;
	for (int i=1;i<=n;i++) 
		s += (p.x[i]-1) * t , t *= (w.x[i]);
	return s+1;
} 

struct Edge{
	int a,b,v,next,o1,o2;
	void print() {
		printf("debug::edge  %d %d %d %d %d\n",a,b,v,o1,o2);
	}
}e[50*N];

void add(int a,int b,int v,int o1,int o2) {
	e[++cnt].a = a;   e[cnt].b = b;   e[cnt].v = v;
	e[cnt].next = h[a];   h[a] = cnt;
	e[cnt].o1 = o1;   e[cnt].o2 = o2;
	return ;
}

void add_Node(int a,int b,int v,int o1,int o2) {
	add(a,b,1-v,o1,o2); add(b,a,v,0,0);
}

bool aq(Node x) {
	for (int i=1;i<=n;i++) if (x.x[i]<1 || x.x[i]>w.x[i]) return 0;
	return 1;
}

void color(Node s) {
	g[0]=g[1]=0;
	for (int i=1;i<=siz;i++) vis[i] = 0;
	
	queue<Node> q; q.push(s); vis[v(s)]=1;
	while (!q.empty()) {
		Node now=q.front(); q.pop();
		int vnow = v(now); ;
		if (v(now) != v(p)) g[ c[vnow] ]++;
		for (int i=1;i<=n;i++)
			for (int j=-1;j<=1;j+=2) {
				Node nxt=now; nxt.x[i] += j;
				if (!aq(nxt)) continue;
				int vxt = v(nxt);
				if (vis[vxt]) continue;
				c[vxt]=c[vnow]^1;
				vis[vxt] = 1;
				q.push(nxt);
			}
	}
	return ;
}

void build(Node s) {
	cnt = 1;
	for (int i=0;i<=siz+5;i++) vis[i] = pp[i] = 0;
	
	queue<Node> q; q.push(s); vis[ v(s) ] = 1;
	while (!q.empty()) {
		Node now=q.front(); q.pop();
		int vnow = v(now);
		for (int i=1;i<=n;i++) 
			for (int j=-1;j<=1;j+=2) {
				Node nxt=now; nxt.x[i] += j;
				if (!aq(nxt)) continue;
				int vxt = v(nxt);
				
				if (c[vnow] == stdpos && !ban[vnow] && !ban[vxt]) {
					if (!pp[vnow] && !pp[vxt]) {
						pp[vnow] = pp[vxt] = 1;
						add_Node(vnow,vxt,1,i,j);
					} else {
						add_Node(vnow,vxt,0,i,j);
					}
				}
				if (vis[vxt]) continue;
				vis[vxt]=1; q.push(nxt);
			}
	}
	
	S = siz+1; T = siz+2;
	for (int i=1;i<=siz;i++) if (!ban[i]){
		if (c[i] == stdpos) 
			add_Node(S,i,pp[i],0,0);
		else
			add_Node(i,T,pp[i],0,0);
	}
		
	return ;
}

#define cp e[i].v
#define B e[i].b
bool BFS() {
    bool flag = 0;
    
    for (int i=0;i<=siz+5;i++) fc[i]=0; fc[S] = 1;
    for (int i=0;i<=siz+5;i++) cur[i] = h[i];
    queue<int> q; q.push(S); 
    while (!q.empty()) {
        int u = q.front(); q.pop();
        if (u == T) flag = 1;
        for (int i=h[u];i;i=e[i].next) 
            if (e[i].v>0 && !fc[B]) {
                fc[B] = fc[u]+1;
                q.push(B);
            }
    }
    return flag;
}
int DFS(int u,int flow) {
    if (u == T) return flow;
    int f = flow , g = 0 , tmp = 0;
    for (int &i=cur[u];i;i=e[i].next)
        if (cp>0 && fc[B]==fc[u]+1 && ( tmp=DFS(B,min(cp,f)) ) > 0) {
            e[i  ].v -= tmp; 
            e[i^1].v += tmp;
            f -= tmp; g += tmp;
        }
    return g;
}

bool X() {
	int x; char ch;
	scanf("%d %c",&x,&ch);
	if (ch == '?') return 0;
	if (ch == '+') p.x[x]++; else p.x[x]--;
	return 1;
}

void Y() {
	int o1=ans?0:INF,o2=ans?0:INF;
	for (int i=h[v(p)];i;i=e[i].next) 
		if (e[i].v==0 && e[i].o2) {
			o1=e[i].o1; o2=e[i].o2; break;
		}
	p.x[o1] += o2;
	printf("%d %c\n",o1,o2>0 ? '+' : '-'); fflush(stdout);
}

int main() {
	while (1) {
		//init();
		scanf("%d",&n); if (n == 0) break;
		for (int i=1;i<=15;i++) if (i<=n) id.x[i]=1; else id.x[i]=0;
		p=w=id;
		for (int i=1;i<=n;i++) scanf("%d",&w.x[i]) , w.x[i]++;
		for (int i=1;i<=n;i++) scanf("%d",&p.x[i]) , p.x[i]++;
		siz = v(w);
		
		ans = false;
		//for (int i=1;i<=n;i++) if (w.x[i]%2 == 0) ans = true;
		
		color(id);
		
		int idc = c[ v(p) ];
		if (g[idc^1] > g[idc]) ans = 1; else ans = 0; //1Alice先手 , 0Bob后手 

		if (ans==1) {
			stdpos = idc;
			printf("Alice\n"); fflush(stdout);
			build(id);
			while (BFS()) DFS(S,INF);
			Y();
		} else {
			stdpos = idc^1;
			printf("Bob\n"); fflush(stdout);
			ban[v(p)] = true;
			build(id);
			while (BFS()) DFS(S,INF);
		}
		while (X()) Y();
		
		//for (int i=2;i<=cnt;i+=2) e[i].print();
		
		for (int i=0;i<=siz+10;i++)
			pp[i]=vis[i]=h[i]=c[i]=ban[i]=0;
		for (int i=1;i<=cnt;i++)
			e[i]=(Edge){0,0,0,0,0,0};
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值