UVA12267 Telephone Network

UVA12267 Telephone Network

nb tea。

注意到如果两个需要相互接通的请求 \(a,b\) 在某一层分别接了上下两个开关,那么接下来它们永远也无法接通了,因为上下两个开关是相互独立的,不会出现上面的开关和下面的开关有连边的情况。

不妨先考虑每个请求如何接第 \(n-1\) 层开关。限制如下:

  • 对于请求 \(i\in [0,2^{n-1})\),显然它们和请求 \(i+2^{n-1}\) 不能同时往上走或往下走,不然就会出现一个节点被两个请求占用的情况。
  • \(a_j\) 和 \(b_j\) 走的方向要相同,即 \(b_j\) 走的方向不能与 \(a_j\) 相反。
  • 请求不能同时往上或往下走。

有这么多限制,这就启发我们用图论的方法解决这道题目:一共有 \(2^{n+2}\) 个节点。第 \(i\in [0,2^n)\) 个节点表示左边第 \(i\) 个请求往上走;第 \(i\in[2^n,2^{n+1})\) 个节点表示左边第 \(i-2^n\) 个请求往下走;第 \(i\in [2^{n+1},3\times 2^n)\) 个节点表示右边第 \(i\) 个请求往上走;第 \(i\in[3\times 2^n,2^{n+2})\) 个节点同理。根据上述三种限制对于两个不能同时发生的事件,我们将其连一条边,最后二分图染色即可。因为保证有解所以不需要考虑无解的情况。

接第 \(n-1\) 层开关的方案有了之后,再类似地去考虑接第 \(n-2,n-3,\cdots,1\) 层开关即可。

时间复杂度 \(\mathcal{O}(Tn2^n)\)。

#include <bits/stdc++.h>
using namespace std;

#define mem(x,v) memset(x,v,sizeof(x))

const int N=16;
int t,n,m,x[1<<N],y[1<<N];
int cnt,vis[4<<N],col[4<<N],hd[4<<N],nxt[12<<N],to[12<<N];
void add(int u,int v){
	nxt[cnt]=hd[u],hd[u]=cnt,to[cnt++]=v;
	nxt[cnt]=hd[v],hd[v]=cnt,to[cnt++]=u;
}
void dfs(int id,int c){
	vis[id]=1,col[id]=c;
	for(int i=hd[id];i;i=nxt[i])if(!vis[to[i]])dfs(to[i],c^1); 
}

void solve(){
	cin>>n>>m;
	for(int i=0;i<m;i++)scanf("%d%d",&x[i],&y[i]);
	for(int i=n-1;~i;i--){
		mem(vis,0),mem(col,0),mem(hd,0),cnt=0;
		for(int j=0;j<m;j++)add(x[j],y[j]+(3<<n)),add(x[j]+(1<<n),y[j]+(2<<n));
		for(int j=0;j<1<<n;j++)add(j,j+(1<<n)),add(j+(2<<n),j+(3<<n));
		for(int j=0;j<1<<n;j++)if((j>>i)&1)
			add(j,j-(1<<i)),add(j+(1<<n),j-(1<<i)+(1<<n)),
			add(j+(2<<n),j+(2<<n)-(1<<i)),
			add(j+(3<<n),j+(3<<n)-(1<<i));
		for(int j=0;j<4<<n;j++)if(!vis[j])dfs(j,0);
		for(int j=0;j<m;j++){
			if(col[x[j]])x[j]-=(x[j]>>i&1)<<i;
			else x[j]+=(!(x[j]>>i&1))<<i;
			if(col[y[j]+(2<<n)])y[j]-=(y[j]>>i&1)<<i;
			else y[j]+=(!(y[j]>>i&1))<<i;
		} 
	}
	for(int i=0;i<m;i++)cout<<x[i]<<(i==m-1?'\n':' ');
}

int main(){
	cin>>t;
	while(t--)solve();
	return 0;
}
上一篇:vue字符串拼接添加点击事件


下一篇:webservice的使用