最近才开始学习状压dp,以前就听听没写过。到目前为止,我对状压dp的应用就是用数位表示点,通过枚举不同的数,也就是不同的到达状态,来实现状态的转移。跟着网上的博客切题中
1.POJ3254 Corn Fields
http://poj.org/problem?id=3254
做的第一个状压题,基本是跟着网上的思路写的,状压dp真是很神奇,通过位运算能解决很多问题。
#include<cstdio>
#include<cstring>
using namespace std;
int ok[1<<13], each[1<<13], cnt;
bool check(int x)
{
return (x&(x<<1));
}
bool check2(int x, int y)
{
return (ok[x]&each[y]);
}
int main()
{
int m, n, a, dp[13][1<<13];
while(~scanf("%d%d", &m, &n))
{
memset(dp, 0, sizeof(dp));
memset(each, 0, sizeof(each));
memset(ok, 0, sizeof(ok));
cnt=0;
for(int i=1; i<=m; i++)
{
for(int j=1; j<=n; j++)
{
scanf("%d", &a);
if(a==0)
{
each[i]+=(1<<(j-1));
}
}
// printf("each[%d]=%d\n", i, each[i]);
}
for(int i=0; i<(1<<n); i++)
{
if(!check(i))
ok[cnt++]=i;
}
for(int i=0; i<cnt; i++)
{
if(!check2(i, 1))
{
dp[1][i]=1;
}
}
for(int i=2; i<=m; i++)
{
for(int j=0; j<cnt; j++)//第i行当前处于j种取值
{
if(check2(j, i))//如果第j种取值不符合规定
continue;
for(int h=0; h<cnt; h++) //第i-1行当前处于h种取值
{
if(check2(h, i-1))
continue;
if(!(ok[j]&ok[h]))
dp[i][j]+=dp[i-1][h];
}
}
}
int ans=0;
for(int i=0; i<cnt; i++)
{
ans+=dp[m][i];
ans%=100000000;
}
printf("%d\n", ans);
}
return 0;
}
2.hdu 3001 Travelling
http://acm.hdu.edu.cn/showproblem.php?pid=3001
因为是最多经过两次,所以用三进制表示,因为习惯了二进制表示,一开始写的很丑而且都调不出bug。除了三进制之外,思路其实差不多。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define INF 0x1f1f1f1f
int dis[15][15];
int index[15] ;
int record[60000][15];
int dp[60000][15];
void init_record()
{
for(int i=0; i<59050; i++)
{
int t = i;
for(int j = 1; j <= 10; ++j){
record[i][j] = t%3;
t /= 3;
if(t == 0)break;
}
}
index[0]=0;
index[1]=1;
for(int i=2; i<=11; i++)
{
index[i]=index[i-1]*3;
}
}
int main()
{
int n, m, a, b, w;
init_record();
while(~scanf("%d%d", &n, &m))
{
memset(dis, INF, sizeof(dis));
for(int i=0; i<m; i++)
{
scanf("%d%d%d", &a, &b, &w);
if(w<dis[a][b])
dis[a][b]=dis[b][a]=w;
}
memset(dp, INF, sizeof(dp));
int ans=INF;
for(int state=1 ; state<index[n+1]; state++)
{
int flag=1;
for(int i=1; i<=n; i++)
{
if(record[state][i]==0)
{
flag=0;continue;
}
if(state==index[i])
{
dp[state][i]=0;
continue;
}
for(int j=1; j<=n; j++)
{
if(i==j) continue;
if(record[state][j]==0||dis[j][i]==INF) continue;
int newstate=state-index[i];
dp[state][i]=min(dp[state][i], dp[newstate][j]+dis[j][i]);
}
}
if(flag)
{
for(int j=1; j<=n; j++)
ans=min(ans, dp[state][j]);
}
}
if(ans==INF)
printf("-1\n");
else
printf("%d\n", ans);
}
return 0;
}
。。。待续