UVA 10891 :
题意: 现在给你一个序列,你可以从序列的左端开始取数,也可以从序列的右端开始取数,每次可以取连续个数,A先取,问A最多比B多取多少。
思路: n为100 显然是区间dp,但是这里也可以用记忆化搜一下呀。这就是一个总和确定的博弈。遇到边界就是l>r ,或者 l==r 。
记忆化代码:
#include<bits/stdc++.h>
using namespace std;
const int inf =0x3f3f3f3f;
int dp[105][105];
int a[105];
int pre[105];
int n;
int dfs(int l,int r,int sum)
{
if(l>r) return 0;
if(l==r) return dp[l][r]=a[l];
if(dp[l][r]!=-1) return dp[l][r];
int res=-inf;
for(int k=l;k<=r;k++){
res=max(res,sum-dfs(k+1,r,sum-(pre[k]-pre[l-1])));
}
for(int k=r;k>=l;k--){
res=max(res,sum-dfs(l,k-1,sum-(pre[r]-pre[k-1])));
}
return dp[l][r]=res;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
memset(dp,-1,sizeof(dp));
int sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
}
for(int i=1;i<=n+2;i++){
if(i>n) pre[i]=0;
else pre[i]=pre[i-1]+a[i];
}
int ans=dfs(1,n,sum);
int b=sum-ans;
printf("%d\n",ans-b);
}
return 0;
}
/*
4
4 -10 -20 7
4
1 2 3 4
0
*/
区间dp代码:
#include<bits/stdc++.h>
#define N 105
#define inf 0x3f3f3f3f
using namespace std;
int dp[N][N];
int a[N];
int sum[N];
int n;
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++) dp[i][i]=a[i];
for(int len=2;len<=n;len++)
{
for(int i=1;i+len-1<=n;i++)
{
int j=i+len-1;
int res=0; // 表示全部拿完
int ssum=sum[j]-sum[i-1];
for(int k=i;k<=j;k++) res=min(res,dp[k][j]);
for(int k=j;k>=i;k--) res=min(res,dp[i][k]);
dp[i][j]=ssum-res;
}
}
/*
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) printf("%d ",dp[i][j]);
printf("\n");
}
*/
int ans=dp[1][n]-(sum[n]-dp[1][n]);
printf("%d\n",ans);
}
return 0;
}
hdu 4597:
题意:现在给你两个序列,你每次可以在两个序列的四个端点随便选择一个数,那么问你先手最多拿多少。
和上边题神似,直接记忆化搜就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N =25;
int a[N];
int b[N];
int dp[25][25][25][25];
int ans[N];
int n;
int dfs(int la,int ra,int lb,int rb,int sum)
{
if(la>ra&&lb>rb) return 0;
if(dp[la][ra][lb][rb]!=-1) return dp[la][ra][lb][rb];
int res=0;
if(la<=ra)
{
res=max(res,sum-dfs(la+1,ra,lb,rb,sum-a[la]));
res=max(res,sum-dfs(la,ra-1,lb,rb,sum-a[ra]));
}
if(lb<=rb){
res=max(res,sum-dfs(la,ra,lb+1,rb,sum-b[lb]));
res=max(res,sum-dfs(la,ra,lb,rb-1,sum-b[rb]));
}
return dp[la][ra][lb][rb]=res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
int sum=0;
for(int i=1;i<=n;i++) sum+=(a[i]+b[i]);
memset(dp,-1,sizeof(dp));
int Ans=dfs(1,n,1,n,sum);
cout<<Ans<<endl;
}
return 0;
}
hdu 4753
题意: 现在有一个九宫格,24条边,A和B轮流加一条边,我如果加了这条边形成了1个1*1的小正方形,那么我得分+1 如果形成了两个,那么得分+2.问你最后谁的得分更高一些。
思路: 因为已经给了你>=12条已经加上的边,所以直接对没有加进去的边状压(不会超过12个)然后搜索一下。
真的傻逼,明明错了却不知道改最容易错的地方,结果改的实在觉得没错了,才他妈想起来是不是预处理。。数字搞错了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int ,int > pii;
const int N =27;
int vis[N][N];
map<pii,int >id;
int mp[N][N];
map<int ,pii>mp1;
int dp[(1<<14)];
int yi[25];
int n;
void init_yi()
{
yi[0]=1;
for(int i=1;i<=21;i++) yi[i]=yi[i-1]*2;
}
void init()
{
int tot=0;
mp[1][2]=1,mp[2][3]=2,mp[3][4]=3;
mp[1][5]=4,mp[2][6]=5,mp[3][7]=6,mp[4][8]=7;
mp[5][6]=8,mp[6][7]=9,mp[7][8]=10;
mp[5][9]=11,mp[6][10]=12,mp[7][11]=13,mp[8][12]=14;
mp[9][10]=15,mp[10][11]=16,mp[11][12]=17;
mp[9][13]=18,mp[10][14]=19,mp[11][15]=20,mp[12][16]=21;
mp[13][14]=22,mp[14][15]=23,mp[15][16]=24;
for(int i=1;i<=16;i++){
for(int j=1;j<=16;j++){
if(mp[i][j]!=0){
mp1[++tot]=pii(i,j);
}
}
}
}
int jud1()
{
if(vis[1][2]&&vis[1][5]&&vis[2][6]&&vis[5][6]) return 1;
return 0;
}
int jud2()
{
if(vis[2][3]&&vis[2][6]&&vis[3][7]&&vis[6][7]) return 1;
return 0;
}
int jud3()
{
if(vis[3][4]&&vis[3][7]&&vis[4][8]&&vis[7][8]) return 1;
return 0;
}
int jud4()
{
if(vis[5][6]&&vis[5][9]&&vis[6][10]&&vis[9][10]) return 1;
return 0;
}
int jud5()
{
if(vis[6][7]&&vis[6][10]&&vis[10][11]&&vis[7][11]) return 1;
return 0;
}
int jud6()
{
if(vis[7][8]&&vis[7][11]&&vis[11][12]&&vis[8][12]) return 1;
return 0;
}
int jud7()
{
if(vis[9][10]&&vis[9][13]&&vis[13][14]&&vis[10][14]) return 1;
return 0;
}
int jud8()
{
if(vis[10][11]&&vis[10][14]&&vis[11][15]&&vis[14][15]) return 1;
return 0;
}
int jud9()
{
if(vis[11][15]&&vis[11][12]&&vis[15][16]&&vis[12][16]) return 1;
return 0;
}
int jud(int x,int y)
{
//cout<<"x "<<x<<" y "<<y<<endl;
int id=mp[x][y];
//cout<<" id "<<id<<endl;
int tmp=0;
if(id==1||id==4||id==5||id==8){
tmp+=jud1();
}
if(id==2||id==5||id==6||id==9){
tmp+=jud2();
}
if(id==3||id==6||id==7||id==10){
tmp+=jud3();
}
if(id==8||id==11||id==12||id==15){
tmp+=jud4();
}
if(id==9||id==12||id==13||id==16){
tmp+=jud5();
}
if(id==10||id==13||id==14||id==17){
tmp+=jud6();
}
if(id==15||id==18||id==19||id==22){
tmp+=jud7();
}
if(id==16||id==19||id==20||id==23){
tmp+=jud8();
}
if(id==17||id==20||id==21||id==24){
tmp+=jud9();
}
return tmp;
}
int up;
int dfs(int s,int sum)
{
//cout<<"s "<<s<<" sum "<<sum<<endl;
/*
if(s==up){
//cout<<".lalalal "<<endl;
return 0;
}
*/
if(dp[s]!=-1) return dp[s];
int res=0;
for(int i=1;i<=24;i++){
int x,y;
x=mp1[i].first; y=mp1[i].second;
if(vis[x][y]) continue;
int idd=yi[id[pii(x,y)]];
if((s&idd)==0){
vis[x][y]=1;
int tmps=(s|idd);
res=max(res,sum-dfs(tmps,sum-jud(x,y)));
vis[x][y]=0;
}
}
return dp[s]=res;
}
int main()
{
init();
init_yi();
int T;
scanf("%d",&T);
int kk=0;
int x,y;
int A,B;
while(T--){
scanf("%d",&n);
A=0; B=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
scanf("%d %d",&x,&y);
if(x>y) swap(x,y);
vis[x][y]=1;
int ju=jud(x,y);
if(ju!=0){
if(i%2==1) A+=ju;
else B+=ju;
}
}
if(A>=5||B>=5){
if(A>=5){
printf("Case #%d: Tom200\n",++kk);
}
else printf("Case #%d: Jerry404\n",++kk);
continue;
}
int sum=9-(A+B);
int tot=0;
id.clear();
for(int i=1;i<=24;i++){
x=mp1[i].first; y=mp1[i].second;
if(x>y) swap(x,y);
if(vis[x][y]) continue;
id[pii(x,y)]=tot++;
//cout<<"x "<<x<<" y "<<y<<" id "<<tot<<endl;
}
up=yi[tot]-1;
memset(dp,-1,sizeof(dp));
int ans=dfs(0,sum);
//cout<<"ans "<<ans<<endl;
if((n+1)%2==1){
A+=ans;
B=9-A;
}
else{
B+=ans;
A=9-B;
}
//cout<<"A "<<A<<" B "<<B<<endl;
if(A>B){
printf("Case #%d: Tom200\n",++kk);
}
else printf("Case #%d: Jerry404\n",++kk);
}
return 0;
}