[at code festival 2016 J]Neue Spiel

每次操作可以看作将物品放到该方向上第一个无物品的位置

从操作向该行/列的位置连边,显然需存在完美匹配,并考虑一组匹配是否合法

限制即每个位置(操作时间)要比所匹配操作方向上之前的位置大,以此连边后无环即合法

当产生环时,考虑调整,将每个操作改为匹配其原来所匹配位置连向的位置

定义势能为总边数,如果每个点依次搜索出边,则恰会以与减少边数相同的代价找到该环

换言之,均摊为\(O(n^{3})\)(包括最终无环的判定),结合二分图匹配,时间复杂度为\(O(n^{3})\)

#include<bits/stdc++.h>
using namespace std;
const int N=305,M=100000; 
int n,T,E,x,flag,head[M],Head[M],d[M],st[M],vis[M],r[M],ans[M];
queue<int>q;vector<int>V,e[M];
struct List{int nex,to,len;}edge[M*10];
void add(int x,int y,int z){
	edge[E]=List{head[x],y,z},head[x]=E++;
	edge[E]=List{head[y],x,0},head[y]=E++;
}
bool bfs(){
	memset(d,-1,sizeof(d));
	d[0]=0,q.push(0);
	while (!q.empty()){
		int k=q.front();q.pop();
		for(int i=head[k];i!=-1;i=edge[i].nex)
			if ((edge[i].len)&&(d[edge[i].to]<0)){
				d[edge[i].to]=d[k]+1,q.push(edge[i].to);
			}
	}
	return d[T]>=0;
}
int dfs(int k,int s){
	if (k==T)return s;
	int ans=0;
	for(int &i=head[k];i!=-1;i=edge[i].nex)
		if ((edge[i].len)&&(d[edge[i].to]==d[k]+1)){
			int p=dfs(edge[i].to,min(s,edge[i].len));
			edge[i].len-=p,edge[i^1].len+=p,s-=p,ans+=p;
			if (!s)break;
		}
	return ans;
} 
int dinic(){
	int ans=0;
	memcpy(Head,head,sizeof(head));
	while (bfs()){
		ans+=dfs(0,0x3f3f3f3f);
		memcpy(head,Head,sizeof(head));
	}
	return ans;
}
int id(int x,int y){
	return (x-1)*n+y+(n<<2);
}
int getx(int k){
	return (k-(n<<2)-1)/n+1;
}
int gety(int k){
	return (k-(n<<2)-1)%n+1;
}
void write(int k){
	if (ans[k]==0)printf("U%d\n",gety(k));
	if (ans[k]==1)printf("D%d\n",gety(k));
	if (ans[k]==2)printf("L%d\n",getx(k));
	if (ans[k]==3)printf("R%d\n",getx(k));
}
void dfs(int k);
bool work(int k,int i){
	if (!vis[i])dfs(i);
	else{
		if (vis[i]==1){
			int s=ans[k];
			while (st[st[0]]!=i){
				ans[st[st[0]]]=ans[st[st[0]-1]];
				vis[st[st[0]--]]=0;
			}
			ans[i]=s,st[0]--,dfs(i);
			return 1;
		}
	}
	return vis[k]!=1;
}
void dfs(int k){
	int x=getx(k),y=gety(k);
	st[++st[0]]=k,vis[k]=1;
	if (ans[k]==0){
		while (--x){
			if (work(k,id(x,y)))return;
		}
	}
	if (ans[k]==1){
		while (++x<=n){
			if (work(k,id(x,y)))return;
		}
	}
	if (ans[k]==2){
		while (--y){
			if (work(k,id(x,y)))return;
		}
	}
	if (ans[k]==3){
		while (++y<=n){
			if (work(k,id(x,y)))return;
		}
	}
	st[0]--,vis[k]=2;
}
int main(){
	scanf("%d",&n),T=id(n,n)+1;
	memset(head,-1,sizeof(head));
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)V.push_back(id(i,j));
	for(int i=1;i<=n;i++){
		scanf("%d",&x),add(0,i,x);
		for(int j=1;j<=n;j++)add(i,id(j,i),1);
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&x),add(0,i+n,x);
		for(int j=1;j<=n;j++)add(i+n,id(j,i),1);
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&x),add(0,i+(n<<1),x);
		for(int j=1;j<=n;j++)add(i+(n<<1),id(i,j),1);
	}
	for(int i=1;i<=n;i++){
		scanf("%d",&x),add(0,i+n*3,x);
		for(int j=1;j<=n;j++)add(i+n*3,id(i,j),1);
	}
	for(int i:V)add(i,T,1);
	if (dinic()!=n*n){
		printf("NO\n");
		return 0;
	}
	for(int I=0;I<4;I++)
		for(int i=1;i<=n;i++)
			for(int j=head[i+n*I];j!=-1;j=edge[j].nex)
				if ((edge[j].to)&&(!edge[j].len))ans[edge[j].to]=I;
	for(int i:V)
		if (!vis[i])dfs(i);
	for(int i:V){
		int x=getx(i),y=gety(i);
		if (ans[i]==0){
			while (--x)r[i]++,e[id(x,y)].push_back(i);
		}
		if (ans[i]==1){
			while (++x<=n)r[i]++,e[id(x,y)].push_back(i);
		}
		if (ans[i]==2){
			while (--y)r[i]++,e[id(x,y)].push_back(i);
		}
		if (ans[i]==3){
			while (++y<=n)r[i]++,e[id(x,y)].push_back(i);
		}
		if (!r[i])q.push(i);
	}
	while (!q.empty()){
		int k=q.front();q.pop();
		write(k);
		for(int i:e[k])
			if (--r[i]==0)q.push(i);
	}
	return 0;
} 
posted @ 2023-02-02 10:56  PYWBKTDA  阅读(65)  评论(0编辑  收藏  举报