CF1147F Zigzag Game

题目链接

尝试构造这样一组匹配:满足对于任意两条匹配边 (aleftrightarrow b,cleftrightarrow d),若存在非匹配边 (bleftrightarrow c)(w(b,c)<w(a,b)),则一定有 (w(c,d))。这样我们选择后手Bob,每次沿着匹配边走,一定能获得胜利(若Alice选择升序则令 (w(i,j)=-w(i,j)) 即可)。

发现这样的构造是一定存在的。对二分图左边的点,我们让优先级为从大到小;对于二分图右边的点,我们让优先级从小到大。然后使用稳定婚姻算法,发现正好可以满足以上条件。时间复杂度 (O(n^2))

代码:

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

using namespace std;

const int N=500,INF=1<<30;
int nxt[N],a[N][N],n,x,Rank[N][N],now;
char s[10];
queue <int> q;

void init()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			scanf("%d",&a[i][j]);
	puts("B");fflush(stdout);
	scanf("%s",s);
	if(s[0]=='I')
	{
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				a[i][j]=-a[i][j];
	}
	scanf("%d",&x);
	if(x>n)
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				a[i][j]=-a[i][j];
}

bool cmp(int x,int y)
{
	return a[now][x-n]>a[now][y-n];
}

void prework()
{
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=n;j++)
			Rank[i][j]=j+n;
		now=i;
		sort(Rank[i]+1,Rank[i]+1+n,cmp);
		q.push(i);
	}
	for (int i=1;i<=n;i++)
		a[0][i]=a[i][0]=INF;
	for (int i=1;i<=n;i++)
		nxt[i]=nxt[i+n]=Rank[i][0]=0;
	while(!q.empty())
	{
		int x=q.front();q.pop();
		if(x==0) continue;
		while(nxt[x]==0)
		{
			int girl=Rank[x][++*Rank[x]];
			if(a[x][girl-n]<a[nxt[girl]][girl-n])
				nxt[nxt[girl]]=0,q.push(nxt[girl]),nxt[girl]=x,nxt[x]=girl;
		}
	}
}

void work()
{
	prework();
	for (int i=1;;i++)
	{
		if(x==-1||x==-2) return;
		printf("%d
",nxt[x]);fflush(stdout);
		scanf("%d",&x);
	}
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		init();
		work();
	}
	return 0;
}

原文地址:https://www.cnblogs.com/With-penguin/p/13676923.html