http://acm.zcmu.edu.cn/JudgeOnline/contest.php?cid=1087

A dp

类似问题:

动态规划专题,留坑待填

最大子矩阵和

...

给定一个矩阵,可以向右走,向上走,向下走但不能向左走,求从左上角走到右下角的最大值

 一列一列考虑 
dp[i][j][3],  后面3个表示从什么方向进入这个点 
假设现在的点为(i,j)
从左边进入的话要考虑点(i,j-1)的情况,取该点左,上,下的最大值

dp[i][j][left]=max(dp[i][j-1][left],dp[i][j-1][up],dp[i][j-1][down])+a[i][j];

从上面进入的话要考虑点(i-1,j)的情况,注意不能走两次
dp[i][j][up]=max(dp[i-1][j][up],dp[i-1][j][left])+a[i][j];

从下面进入的话要考虑点(i+1,j)的情况,注意不能走两次
dp[i][j][down]=max(dp[i+1][j][down],dp[i+1][j][left])+a[i][j];

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define rep2(i,n) for(int i=1;i<=n;i++)
#define per2(i,n) for(int i=n;i>=1;i--)
int max(int a,int b,int c){return max(max(a,b),c);}
int min(int a,int b,int c){return min(min(a,b),c);}
int getint() {
    int ret=0;bool ok=0,neg=0;
    for(;;) {
        int c=getchar();
        if(c>='0'&&c<='9')ret=(ret<<3)+ret+ret+c-'0',ok=1;
        else if(ok)return neg?-ret:ret;
        else if(c=='-')neg=1;
    }
}
//--------IO--------
#define up 0
#define down 1
#define left 2
int n,m;
int a[110][110];
void slove()
{
    int dp[110][110][3];
    rep(i,n+2)rep(j,n+2)rep(k,3)dp[i][j][k]=-999999999;
    dp[0][1][up]=0;
    rep2(j,m)
    {
        rep2(i,n){
            dp[i][j][left]=max(dp[i][j-1][left],dp[i][j-1][up],dp[i][j-1][down])+a[i][j];
        }
        rep2(i,n){
            dp[i][j][up]=max(dp[i-1][j][up],dp[i-1][j][left])+a[i][j];
        }
        per2(i,n){
            dp[i][j][down]=max(dp[i+1][j][down],dp[i+1][j][left])+a[i][j];
        }
    }
    printf("%d\n",max(dp[n][m][left],dp[n][m][up],dp[n][m][down]));
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        n=getint(),m=getint();
        rep2(i,n)rep2(j,m)a[i][j]=getint();
        slove();
    }
    return 0;
}
View Code

 

AA 水,最小表示法

有3中情况

(1). s[p1+k] > s[p2+k],则p1滑动到p1+k+1处 --- 即s1[p1->p1+k]不会是该循环字符串的“最小表示”的前缀。

(2). s[p1+k] < s[p2+k],则p2滑动到p2+k+1处,原因同上。

(3). s[p1+k] = s[p2+k],则 k++; if (k == len) 返回结果。

注:这里滑动方式有个小细节,若滑动后p1 == p2,将正在变化的那个指针再+1。直到p1、p2把整个字符串都检验完毕,返回两者中小于 len 的值。

最小表示法 zoj1729

http://www.cnblogs.com/wuyiqi/archive/2012/03/17/2403927.html

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char s[100010];
void slove()
{
    int i=0,j=1,k=0;
    int len=strlen(s);
    while(i<len&&j<len&&k<len)
    {
        int tmp=s[(i+k)%len]-s[(j+k)%len];
        if(tmp==0)
            k++;
        else
        {
            if(tmp>0)i=i+k+1;//i~i+k 都不可能是最小前缀
            else j=j+k+1;
            if(i==j)j++;
            k=0;
        }
    }
    printf("%d\n",i<j?i:j);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",s);
        slove();
    }
    return 0;
}
View Code

 

 

AAA 状压dp zoj3777

用dfs的话时间复杂度为12!,大约4亿,肯定超时

dp[i][j]表示取i的二进制位为1的值兴趣值为j时的个数。
(当i&(1<<(j-1))==0)dp[i|(1<<(j-1))][k+a[tmp+1][j]] += dp[i][k]; 01背包

#include<cstdio>
#include<cstring>
#include<iostream>
int dp[4500][550];//1<<12
int a[20][20];
int n,m;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                scanf("%d",&a[i][j]);
        }
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        int ALL=1<<n;
        for(int i=0;i<ALL-1;i++)
        {
            int sloved=0;
            for(int j=1;j<=n;j++)//计算i中1的个数
            {
                if(i&(1<<(j-1)))sloved++;
            }
            for(int j=1;j<=n;j++)
            {
                if(i&(1<<(j-1)))continue;//检查j列是否被占用
                for(int k=0;k<=m;k++)
                {
                    //>=m的情况数目都放在m里面
                    if(k+a[sloved+1][j]>=m)dp[i|(1<<(j-1))][m]+=dp[i][k];
                    else dp[i|(1<<(j-1))][k+a[sloved+1][j]]+=dp[i][k];
                }
            }
        }
        if(dp[(1<<n)-1][m])printf("%d\n",dp[(1<<n)-1][m]);
        else puts("No solution");
    }
    return 0;
}
View Code

 

 用dfs超时的代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int mp[20][20];
bool vis[20];
int n,m;
int cnt;
int getint() {
    int ret=0;bool ok=0,neg=0;
    for(;;) {
        int c=getchar();
        if(c>='0'&&c<='9')ret=(ret<<3)+ret+ret+c-'0',ok=1;
        else if(ok)return neg?-ret:ret;
        else if(c=='-')neg=1;
    }
}
void dfs(int k,int sum)
{
  //  printf("%d %d\n",k,sum);
    if(k==n)
    {
        if(sum>=m)cnt++;
        return;
    }
    for(int i=0;i<n;i++)
    {
        if(!vis[i])
        {
            vis[i]=true;
            dfs(k+1,sum+mp[k][i]);
            vis[i]=false;
        }
    }
}
int main()
{
    int T;
    T=getint();
    while(T--)
    {
        n=getint(),m=getint();
        memset(vis,false,sizeof(vis));
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)mp[i][j]=getint();
        }
        cnt=0;
        dfs(0,0);
        if(cnt)printf("%d\n",cnt);
        else puts("No solution");
    }
    return 0;
}
View Code

 

AAAA 水 用递归画图

#include<iostream>
#include<cstdio>
using namespace std;
char s[800][800];
int val[10];
void dfs(int x,int y,int level)
{
    if(level==1){
        s[x][y]='+';
        return;
    }
    int d=val[level-1];
    dfs(x,y,level-1);
    dfs(x-d,y,level-1);
    dfs(x+d,y,level-1);
    dfs(x,y-d,level-1);
    dfs(x,y+d,level-1);
}
int main()
{
    int n;
    val[1]=1;
    for(int i=2;i<8;i++)val[i]=val[i-1]*3;
    int flag=1;
    while(~scanf("%d",&n))
    {
        if(flag)flag=0;
        else puts("");
        for(int i=0;i<800;i++)
        {
            for(int j=0;j<800;j++)s[i][j]=' ';
        }
        dfs(val[n]/2,val[n]/2,n);
        for(int i=0;i<val[n];i++)
        {
            for(int j=val[n]-1;j>=0;j--)
            {
                if(s[i][j]!=' ')
                {
                    s[i][j+1]='\0';
                    break;
                }
            }
            puts(s[i]);
        }
    }
    return 0;
}
View Code

 

AAAAA 水,模拟

浮点数补0  printf("%05.2f",5.2); 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char str[110];
struct ss
{
    int val;
    char str[110];
}a[10010];
int num=0;
bool cmp(ss a, ss b)
{
    return a.val<b.val;
}
int gettime(char *s,int l,int r)
{
    int mm=0,ss=0,ff=0,i=l;
    while(i<=r&&s[i]!=':')mm=mm*10+s[i++]-'0';
    i++;
    while(i<=r&&s[i]!='.')ss=ss*10+s[i++]-'0';
    i++;
    while(i<=r)ff=ff*10+s[i++]-'0';
    return mm*10000+ss*100+ff;
}
int main()
{
   // freopen("tes.in","r",stdin);
    while(gets(str))
    {
        int len=strlen(str);
        int pstr;
        for(int i=len-1;i>=0;i--)
        {
            if(str[i]==']'){
                pstr=i;
                break;
            }
        }
        char s[110];
        int pp=0;
        for(int i=pstr+1;i<len;i++)s[pp++]=str[i];
        s[pp]='\0';
 
        int i=0;
        while(i<=pstr)
        {
            int l,r;
            while(i<=pstr&&str[i]!='[')i++;
            l=i+1;
            while(i<=pstr&&str[i]!=']')i++;
            r=i-1;
            if(l>r)break;
            int t=gettime(str,l,r);
            a[num].val=t;
            strcpy(a[num].str,s);
            num++;
        }
    }
    sort(a,a+num,cmp);
    for(int i=0;i<num;i++)printf("[%02d:%02d.%02d]%s\n",a[i].val/10000,a[i].val%10000/100,a[i].val%100,a[i].str);
    return 0;
}
View Code

 

posted on 2015-04-06 20:13  kylehz  阅读(217)  评论(0)    收藏  举报