有些题目打得比较幼稚。。。
贴这些主要是收集状压Dp
jzoj 1340周长:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace std;
int f[32768][16],a[21];
long long fa[32768][16];
int main()
{
int n;
int p=0,t=0;
scanf("%d",&n);
int two[17]{0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
f[two[i]][i]=a[i]+2;
fa[two[i]][i]=1;
}
int m=two[n+1]-1;
long long ans=-2147483647;
long long sum=0;
for (int i=1;i<=m;i++)
{
for (int j=1;j<=n;j++)
{
if ((i & two[j])!=0)
for (int k=1;k<=n;k++)
if (( two[k] & i)==0)
{
p=i+two[k];
t=f[i][j]+2+abs(a[k]-a[j]);
if (t==f[p][k]) fa[p][k]=fa[i][j]+fa[p][k];
else if (t>f[p][k])
{
f[p][k]=t;
fa[p][k]=fa[i][j];
}
}
if (ans==f[i][j]+a[j]) sum+=fa[i][j];
else if (ans<(f[i][j]+a[j]))
{
ans=f[i][j]+a[j];
sum=fa[i][j];
}
}
}
printf("%lld %lld",ans,sum);
}
jzoj 1768. 【NOI2001】炮兵阵地【难】
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#define N 200
#define fo(i,a,b) for (int i=a;i<=b;i++)
using namespace std;
int n,m,G[N],b[N],F[N][N][N],sum[N],tot=0;
char ch;
bool pd(int x)
{
if (x&(x<<1)) return false;
if (x&(x<<2)) return false;
return true;
}
int GetSum(int x)
{
int S=0;
while (x)
{
if (x&1) S++;
x>>=1;
}
return S;
}
int main()
{
freopen("data10.in","r",stdin);
scanf("%d%d",&n,&m);
fo(i,1,n)
fo(j,1,m)
{
cin>>ch;
if (ch=='H') G[i]+=1<<(j-1);
}
int p=(1<<m)-1;
tot=0;
fo(i,0,p)
if (pd(i))
{
b[++tot]=i;
sum[tot]=GetSum(i);
}
memset(F,255,sizeof(F));
fo(i,1,tot)
if (!(G[1]&b[i])) F[1][1][i]=sum[i];
fo(i,1,n)
fo(j,1,tot)
if (!(G[i]&b[j]))
fo(k,1,tot)
if (!(b[j]&b[k]))
{
fo(l,1,tot)
if (!(b[j]&b[l]))
{
int q=F[i-1][l][k]+sum[j];
if (F[i-1][l][k]!=-1) F[i][k][j]=max(F[i][k][j],q);
}
}
int ans=0;
fo(i,1,tot)
fo(j,1,tot) ans=max(ans,F[n][i][j]);
printf("%d",ans);
}
另一种写法
#include<cstdio>
int max(int a,int b){return a>b?a:b;}
int dp[100][100][100];
int st[100];//每种状态的二进制数
int sum[100];//每种状态的炮塔数
int col[100];//按列存放每一行1(指高地)的分布
int cnt;//合法状态总数
char s[10];
bool J(int x){//判断状态是否合法(每两个1中间至少有2个0)
if(x&(x<<1))return 0;
if(x&(x<<2))return 0;
return 1;
}
int getSum(int x){//获得状态x下所安置的炮塔数(即求x有多少个二进制位1)
int res=0;
while(x){
if(x&1)res++;
x>>=1;
}
return res;
}
void pre(int m){//预处理出所有合法状态及该状态下炮塔数
int i,e=1<<m;
cnt=0;
for(i=0;i<e;i++)
{
if(J(i))st[cnt]=i,sum[cnt++]=getSum(i);
}
}
void clear(int x){
for(int i=0;i<cnt;i++)for(int j=0;j<cnt;j++)dp[x][i][j]=-1;
}
int main(){
freopen("data10.in","r",stdin);
int n,m,i,j,r1,r2;
while(~scanf("%d%d",&n,&m)){
pre(m);
for(i=0;i<n;i++)col[i]=0;
for(i=0;i<n;i++){
scanf("%s",s);
for(j=0;j<m;j++)if(s[j]=='H')col[i]|=(1<<j);
}
for(i=0;i<n;i++)clear(i);
for(i=0;i<cnt;i++)if(!(col[0]&st[i]))dp[0][0][i]=sum[i];//第0行
for(i=1;i<n;i++){
for(j=0;j<cnt;j++)if(!(col[i]&st[j])){//当前行状态(高地与当前状态不冲突)
for(r1=0;r1<cnt;r1++)if(!(st[j]&st[r1])){//前一行状态(与当前状态不冲突)
for(r2=0;r2<cnt;r2++)if(!(st[j]&st[r2])){//前二行状态(与当前状态不冲突)
if(dp[i-1][r2][r1]!=-1)dp[i][r1][j]=max(dp[i][r1][j],dp[i-1][r2][r1]+sum[j]);
}
}
}
}
int ans=0;
for(i=0;i<cnt;i++)for(j=0;j<cnt;j++)ans=max(ans,dp[n-1][i][j]);
printf("%d\n",ans);
}
return 0;
}
jzoj 1389. 玩诈欺的小杉【推荐】
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for (int i=a;i<=b;i++)
using namespace std;
char c;
int n,m,T;
int F[30],ans=0,p,now,x,Temp,Before;
void Work(int x)
{
now=x;Before=0;
fo(i,1,m)
{
Temp=now;
now=((now>>1)^(now>>2)^(now<<1)^(now<<2)^Before^now^F[i])&p;
Before=Temp;
}
if (!(now)) ans++;
}
int main()
{
//freopen("1389.in","r",stdin);
int T;
scanf("%d%d%d",&n,&m,&T);
while (T--)
{
memset(F,0,sizeof(F));
ans=0;
p=(1<<(n))-1;
fo(i,1,n)
fo(j,1,m)
{
c=getchar();
while(c!='0' && c!='1')c=getchar();
if (c=='1') F[j]=F[j]+(1<<(i-1));
}
fo(i,0,p) Work(i);
printf("%d\n",ans);
}
}
jzoj 1060. 五子棋
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#define N 15
using namespace std;
int a[N][N],b[N][N],c[N],f[N][8192];
int main()
{
//freopen("data10.in","r",stdin);
//freopen("data.out","w",stdout);
int T,n,x;
int two[15]{0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192};
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
memset(f,0,sizeof(f));
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%d",&b[i][j]);
for (int i=1;i<=n;i++)
scanf("%d",&c[i]);
int m=two[n+1]-1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
for (int k=2;k<=n;k++)
if (!(j&two[k]))
{
int x=c[1];
for (int l=2;l<=n;l++)
if ((j&two[l])) x+=a[1][l];
int p=j+two[k];
if (x>c[k]) f[i+1][p]=max(f[i+1][p],f[i][j]+b[1][k]);
else f[i+1][p]=max(f[i+1][p],f[i][j]);
}
}
printf("%d\n",f[n][m]);
}
return 0;
}