トピック:クリック-POJ 1185
イタリアということ:指定された文字列マップ、砲兵攻撃範囲、上下のグリッド内に置く大砲2個の正方形について、Hは場所の大砲に置くことができない頼む、の間、大砲がお互いを攻撃することはできませんどのように多くの砲兵マップは、ほとんどを置きます。
私はいくつかの詳細に注意を払っていない、非常に長い時間を書きました。。。。まず、タイトル、メートルの範囲は状態、分析のための単一のグリッドを圧縮することができる時間がPまたは保留を配置することができるときに、その後、私は2つのセルを検討する必要性について失望のlet大砲、Aされていません状態は良好事前に列挙することはできません頂点の最大数、状態遷移の問題、の右下に現在のグリッドを考えるようになりました。
T.直接的列挙(1 << M)場合両側、はるかに簡単になり、直接状態上方確かにそれを書き込むための最大時間は2行を考えます プレイテーブルはよりやりたいので、お互い砲攻撃少ない60の最大値よりも2人の出会いを配置する行を見つけます。前処理ライン生存状態、次いでHをチェックすることを忘れないで、1は0手段Hを配置することができない配置されない放電を表します。
DP [I] [J] [ K]: i番目のバンクの行状態でロウ状態jのK。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
char a[110][12];
int s[63];//两个炮兵相互不攻击的状态
int book[63];//状态中放了多少个炮兵
int n,m;
int dp[105][63][63];//第i行 上一行的状态是j 这一行的状态k 最大炮兵数
inline bool check(int y)
{
int i=0;
while(i<m)
{
if((1<<i)&y)
{
i++;
if(i>=m)
return true;
if(((1<<i)&y))
return false;
i++;
if(i>=m)
return true;
if(((1<<i)&y))
return false;
}
else
i++;
}
return true;
}
inline int solve(int x)
{
int cnt=0;
for(int i=0;i<m;i++)
{
if(x&(1<<i))
cnt++;
}
return cnt;
}
inline bool check1(int x,int y)
{
int cnt=0;
for(int i=m-1;i>=0;i--,cnt++)
{
if(a[x][i]=='H')
{
if(!((1<<cnt)&y))
continue;
else
return false;
}
}
return true;
}
int main()
{
memset(book,0,sizeof(book));
memset(dp,0,sizeof(dp));
int i,j,k;
int len=0;
scanf("%d %d",&n,&m);
for(i=0;i<n;i++)
scanf("%s",a[i]);
for(i=0;i<(1<<m);i++)
{
if(check(i))
{
book[len]=solve(i);
s[len++]=i;
}
}
for(k=0;k<len;k++)
{
if(check1(0,s[k]))
dp[0][0][k]=book[k];
}
for(i=0;i<len;i++)
{
for(j=0;j<len;j++)
{
if((s[i]&s[j])==0&&check1(0,s[i])&&check1(1,s[j]))
dp[1][i][j]=max(book[j]+dp[0][0][i],dp[1][i][j]);
}
}
for(i=2;i<n;i++)//第i行
{
for(j=0;j<len;j++)//第i-1行的状态
{
if((check1(i-1,s[j]))==false)
continue;
for(k=0;k<len;k++)//第i行的状态
{
if((check1(i,s[k]))==false)
continue;
for(int hh=0;hh<len;hh++)//第i-2行的状态
{
if((check1(i-2,s[hh]))==false)
continue;
if((s[j]&s[k])||(s[j]&s[hh])||(s[k]&s[hh]))
{
continue;
}
dp[i][j][k]=max(dp[i][j][k],book[k]+dp[i-1][hh][j]);
}
}
}
}
int ans=0;
for(i=0;i<len;i++)
{
for(j=0;j<len;j++)
{
if(s[i]&s[j])
continue;
ans=max(ans,dp[n-1][i][j]);
}
}
printf("%d",ans);
return 0;
}
トピック:クリック-3254 POJ
質問の意味:グラフを考えると、1は牛、0いや、ない牛グリッド隣接する同じ時間を表し、完全にどのように多くの方法を尋ねます。
上のタイトルを持つ特定の分析、我々は唯一の牛ならば、状態ライン、プレトリップ検査および実行可能な状態0を知っておく必要があります。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
const int mod=100000000;
int a[15][15];
int dp[15][400];//第i行 j状态的MAX方法数
int s[400];//一行可存在的状态
int n,m;
inline bool check(int y)
{
int i=0;
while(i<m)
{
if((1<<i)&y)
{
i++;
if(i>=m)
return true;
if(((1<<i)&y))
return false;
}
else
i++;
}
return true;
}
inline bool check1(int x,int y)
{
int cnt=0;
for(int i=m-1;i>=0;i--,cnt++)
{
if(a[x][i]==0)
{
if((1<<cnt)&y)
{
return false;
}
else
continue;
}
}
return true;
}
int main()
{
memset(dp,0,sizeof(dp));
int i,j,k;
int len=0;
scanf("%d %d",&n,&m);
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
cin>>a[i][j];
}
}
for(i=0;i<(1<<m);i++)
{
if(check(i))
{
s[len++]=i;
}
}
for(i=0;i<len;i++)
{
if(check1(0,s[i]))
dp[0][i]=1;
}
for(i=1;i<n;i++)
{
for(j=0;j<len;j++)//本行
{
if((check1(i,s[j]))==false)
continue;
for(k=0;k<len;k++)//上一行行状态
{
if((check1(i-1,s[k]))==false)
continue;
if(s[j]&s[k])
continue;
dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;
}
}
}
int ans=0;
for(i=0;i<len;i++)
{
ans+=dp[n-1][i];
ans%=mod;
}
printf("%d",ans);
return 0;
}