蒜头君收到了一个生日礼物——一盒精美的蜡笔,这可把他高兴坏了。蒜头君在完成一道图论的题目后,拿着蜡笔想给题目上的一个无向图进行填色。无向图上一共有 nn 个点,编号从 00 到 n - 1n−1,那么该图就会有 2^n - 12n−1 个非空子图。
蒜头君想给每 ii 个子图进行填色,使得任意一条边连接的两个点的颜色不同,现在他想知道给第 ii 个子图填色,最少需要多少种不同的颜色,记为 s_isi。蒜头君想请你帮他计算一下以下式子的结果:
\displaystyle \sum_{i = 1}^{2^n-1} s_i \times 233^{i}.i=1∑2n−1si×233i.
输入格式
第一行输入一个整数 nn(1\leq n\leq 161≤n≤16),表示无向图有 nn 个点。
接下来输入一个 n \times nn×n 的 0101 矩阵,表示无向图边的情况。如果 a[i][j] = 1a[i][j]=1,则说明 ii 与 jj之间有边相连,如果 a[i][j] = 0a[i][j]=0,则表示 ii与 jj 之间没有边相连。
输出格式
输出一行,输出上述式子的结果,结果可能会很大,输出结果对 2^{32}232 取余的结果即可。
样例输入
4 0111 1011 1101 1110
样例输出
1595912448
解题说明:初始化出所有只涂一个颜色的子图。记这样的子图dp[i]=1;节点少的子图去更新节点都的子图,
dp[i]=min(dp[i],dp[j^i]+dp[j]);图的两个子图集的涂色数相加。比如1-2-3-4-5-6这样的图,我们预处理时会得到dp[图:1-3-5]=1,dp[图:2-4-6]=1
那么dp[1-2-3-4-5-6]更新时就会变成2;
没啥说的,这题卡了我好久!本地对了就是对了,线上提交错误说明oj有问题!。。。。。我忘记初始了。每轮i循坏mn都需要置为无穷大,见鬼了。
AC代码:
#include<iostream>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
const int inf=0x3f3f3f3f;
int dp[1<<16];
int a[20][20];
bool mark[1<<16];
unsigned int powdiy(int x,int y){
unsigned int re=1,be=x;
while(y){
if(y&1)re*=be;
be*=be;
y>>=1;
}
return re;
}
void judge(int x){
int tot=1;
int cot=0;
int note[20];
int temp=x;
while(x){
if(x&1){
note[cot++]=tot;
}
x>>=1;
tot++;
}
for(int i=0;i<cot-1;i++)
for(int j=i+1;j<cot;j++){
if(a[note[i]][note[j]]){
return ;
}
}
dp[temp]=1;
return ;
}
unsigned int sum=0;
int main(){
int n;cin>>n;
memset(dp,inf,sizeof(dp));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
scanf("%1d",&a[i][j]);
}
for(int i=1;i<(1<<n);i++){
judge(i);
}
for(int i=1;i<(1<<n);i++){
int mn=inf;
for(int j=i;j;j=(j-1)&i){
dp[i]=min(dp[i],dp[j^i]+dp[j]);
mn=min(dp[i],mn);
}
sum+=(mn*powdiy(233,i));
}
cout<<sum<<endl;
return 0;
}