计蒜客 蒜头君的蜡笔

问题描述

蒜头君收到了一个生日礼物——一盒精美的蜡笔,这可把他高兴坏了。蒜头君在完成一道图论的题目后,拿着蜡笔想给题目上的一个无向图进行填色。无向图上一共有 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;
	}
	

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值