计蒜客 蒜头君的蜡笔

问题描述

蒜头君收到了一个生日礼物——一盒精美的蜡笔,这可把他高兴坏了。蒜头君在完成一道图论的题目后,拿着蜡笔想给题目上的一个无向图进行填色。无向图上一共有 n 个点,编号从 0 到 n - 1,那么该图就会有 2^n - 1个非空子图。  蒜头君想给每 i 个子图进行填色,使得任意一条边连接的两个点的颜色不同,现在他想知道给第 i 个子图填色,最少需要多少种不同的颜色,记为 s i ​。蒜头君想请你帮他计算一下以下式子的结果:

输入格式

第一行输入一个整数 n(1≤n≤16),表示无向图有 n个点。  

接下来输入一个n×n 的 0101 矩阵,表示无向图边的情况。如果 a[i][j] = 1,则说明 i与 j之间有边相连,如果 a[i][j] =0,则表示 i与j之间没有边相连。

输出格式

输出一行,输出上述式子的结果,结果可能会很大,输出结果对 2^{32}取余的结果即可。

样例输入

40111101111011110

样例输出

1595912448

刚看到此题,%2^32.......怎么办,学到了学到了

可用unsigned int 自然溢出模拟%2^{32}。Unsigned longlong 可用来模拟%2^{64}。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned int ui;
ui cnt=0,dp[1<<17]={0};
int minx=0x3f3f3f3f;
int n;
ui pow_x(ui a,ui b)
{
	ui res=1,temp=a;
	while(b){
		if(b&1){
			res=res*temp;
		}
		temp=temp*temp;
		b>>=1;
	}
	return res;
}
int a[20][20]={{0}};
bool flag[(1<<16)+10]={0};//用来标志该组此数是否在其中 
int check(int k){
	memset(flag,0,sizeof(flag));//每次调用都需初始化 
	for(int i=0;i<n;i++){
		if(k &(1<<i)){
			flag[i+1]=true;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a[i][j]&&flag[i]&&flag[j])
			   return 0;
		}
	}
	return 1;
}
int main(){
	char c;
	scanf("%d",&n);	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>c;
			a[i][j]=c-'0';
			}
		}
	for(int i=1;i<(1<<n);i++){
		if(check(i)) dp[i]=1;
		else{
			dp[i]=minx;
				for(int j=i;j;j=(j-1)&i){
					dp[i]=min(dp[i],dp[j]+dp[j^i]);
				}
			}
		}
	int p=233;
	for(int i=1;i<(1<<n);i++){
		ui tt=pow_x(p,i)*dp[i];
		cnt+=tt;
	}
	cout<<cnt<<endl;
	return 0;
	}
	

猜你喜欢

转载自blog.csdn.net/amf12345/article/details/89009948
今日推荐