动态规划(二)

状态压缩DP

POJ 2441: Arrange the Bulls
表示前i头cow,目前畜栏使用情况为j的方案数。
初值:
转移方程:
目标:
ps:注意需要使用滚动数组防止MLE,加入剪枝(如果目前状态方案数为0则不转移)防止TLE,加入清空滚动数组的操作防止WA。
代码如下

/*

*/
#define method_1
#ifdef method_1
/*
d[i,j]表示前i头cow,目前畜栏使用情况为j的方案数。
初值:d[0,0]=1
转移方程:d[i,j|(1<
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=20+2;
const int INF=0x3f3f3f3f;
int d[2][(1<v[maxn];
void dp(){
    d[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=(1<>n>>m;
    for(int i=1;i<=n;i++){
        int num;
        cin>>num;
        while(num--){
            int temp;
            cin>>temp;
            v[i].push_back(temp-1);
        }
    }
    dp();
    cout<

POJ 3254: Corn Fields
预处理出use数组表示可行的二进制数集合。
表示前i行,第i行状态为j的方案数。在保证第i行和第i-1行状态不矛盾 且和土地使用条件不矛盾 的情况下转移即可。
代码如下

/*
预处理出use数组表示可行的二进制数集合。 
d[i,j]表示前i行,第i行状态为j的方案数。在保证第i行和第i-1行状态不矛盾 且和土地使用条件不矛盾 的情况下转移即可。 
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=12+2;
const int INF=0x3f3f3f3f;
const int mod=100000000;
int d[maxn][(1<use;
bool check(int x){
    int last=0;
    while(x){
        int now=x&1;
        x/=2;
        if(now==1&&last==1) return false;
        last=now;
    }
    return true;
}
void pre(){
    for(int i=0;i<(1<>n>>m;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) cin>>a[i][j];
    for(int i=1;i<=n;i++){
        int sum=0;
        for(int j=1;j<=m;j++){
            sum=sum*2+a[i][j];
        }
        b[i]=(1<

POJ 2836: Rectangular Covering
任意两个点可以确定一个矩形。(分别作为左下角和右上角)于是预处理出所有这样n*n个矩形的覆盖点集和面积进行状态压缩dp。
表示目前覆盖状态为i的最小面积和。(注意重合的面积,重合几次就计算几次)
初值:,其他为INF
目标:
转移方程:
其中
表示i点和j点分别作为左下角和右上角构成的矩形能够覆盖的点集。
表示i点和j点分别作为左下角和右上角构成的矩形的面积。
代码如下

/*

*/
#define method_1
#ifdef method_1
/*
任意两个点可以确定一个矩形。(分别作为左下角和右上角)于是预处理出所有这样n*n个矩形的覆盖点集和面积进行状态压缩dp。
d[i]表示目前覆盖状态为i的最小面积和。(注意重合的面积,重合几次就计算几次) 
初值:d[0]=0,其他为INF 
目标:d[(1<
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=15+2;
const int INF=0x3f3f3f3f;
int n,x[maxn],y[maxn],d[(1<=X1&&x[i]<=X2&&y[i]>=Y1&&y[i]<=Y2) res|=1<>n){
        if(!n) break;
        for(int i=1;i<=n;i++) cin>>x[i]>>y[i];  
        init();
        pre();
        dp();
        cout<

POJ 1795: DNA Laboratory
题解链接:https://blog.csdn.net/qq_29169749/article/details/54755026
PS:注意dp中的顺序问题,详见注释。
代码如下

/*
题解链接:https://blog.csdn.net/qq_29169749/article/details/54755026
PS:注意dp中的顺序问题,详见注释。 
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=15+2;
const int INF=0x3f3f3f3f;
string str[maxn],ans;
int T,n,kase=0,cost[maxn][maxn],d[maxn][(1<=0;k--){ //k=0时没有重合 
                if(str[i].substr(str[i].length()-k)==str[j].substr(0,k)){
                    cost[i][j]=str[i].length()-k;
                    break;
                }
            }
        }
    }
    /*
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            D(cost[i][j]);
        }
        E;
    } 
    */
}
void dp(){
    memset(d,INF,sizeof(d));
    for(int i=1;i<=n;i++){
        d[i][1<>T;
    while(T--){
        cout<<"Scenario #"<<++kase<<":"<>n;
        for(int i=1;i<=n;i++) cin>>str[i];
        if(n==1){
            cout<

POJ 3411: Paid Roads
dijkstra即可。
注意由于有些点可能会反复经过,所以第一维枚举难以有固定顺序,不能用循环来进行状态压缩dp。
代码如下

/*
dijkstra即可。
注意由于有些点可能会反复经过,所以第一维枚举难以有固定顺序,不能用循环来进行状态压缩dp。 
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=10+2;
const int INF=0x3f3f3f3f;
int n,m,vis[maxn][(1<h.c;}
};
priority_queueq;
int bfs(){
    node nd;nd.c=0,nd.p=1,nd.sta=1;
//  q.push((node){1,1,0}); //POJ会ce 
    q.push(nd); 
    while(q.size()){
        node now=q.top();q.pop();
        if(now.p==n) return now.c;
        if(vis[now.p][now.sta]) continue;
        vis[now.p][now.sta]=1;
        for(int i=1;i<=m;i++){
            if(e[i].a!=now.p) continue;
            int dis=now.c+e[i].r;
            if((now.sta|(1<>n>>m;
    for(int i=1;i<=m;i++) cin>>e[i].a>>e[i].b>>e[i].c>>e[i].p>>e[i].r;
    int ans=bfs();
    ans==INF?cout<<"impossible":cout<

矩阵的幂

POJ 3420: Quad Tiling
找规律发现:f(n)=f(n-1)+4f(n-2)+2f(n-3)+3f(n-4)+2f(n-5)+3f(n-6)+...
f(n)-f(n-2)=f(n-1)+4f(n-2)+f(n-3)-f(n-4)
即f(n)=f(n-1)+5f(n-2)+f(n-3)-f(n-4)
最后用矩阵优化递推即可。
注意找递推规律时,注意不重不漏的原则,不能让矩形可以从中分割出来成为两个独立的小部分。
ps:一个天坑在于,这个递推公式递推时,直接取模可能算出负数,所以要处理一下。
代码如下

/*
找规律发现:f(n)=f(n-1)+4f(n-2)+2f(n-3)+3f(n-4)+2f(n-5)+3f(n-6)+...
f(n)-f(n-2)=f(n-1)+4f(n-2)+f(n-3)-f(n-4)
即f(n)=f(n-1)+5f(n-2)+f(n-3)-f(n-4)
最后用矩阵优化递推即可。 
注意找递推规律时,注意不重不漏的原则,不能让矩形可以从中分割出来成为两个独立的小部分。 
ps:一个天坑在于,这个递推公式递推时,直接取模可能算出负数,所以要处理一下。 
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=10+5;
const int INF=0x3f3f3f3f;
int n,m,e[maxn][maxn],p=4,f[maxn];
void init(){
    memset(e,0,sizeof(e));
    e[1][1]=1;e[1][2]=5;e[1][3]=1;e[1][4]=-1;
    e[2][1]=1;e[3][2]=1;e[4][3]=1;
    f[1]=36%m;f[2]=11%m;f[3]=5%m;f[4]=1%m;
}
void mulself(int a[maxn][maxn],int b[maxn][maxn]){
    int temp[maxn][maxn]={0};
    for(int i=1;i<=p;i++) for(int j=1;j<=p;j++) for(int k=1;k<=p;k++) temp[i][j]=(temp[i][j]+a[i][k]*b[k][j]%m+m)%m;//注意要先加m再取模 
    memcpy(a,temp,sizeof(temp));
}
void mul(int b[maxn][maxn],int a[maxn]){
    int temp[maxn]={0};
    for(int i=1;i<=p;i++) for(int j=1;j<=p;j++) temp[i]=(temp[i]+b[i][j]*a[j]%m+m)%m;
    memcpy(a,temp,sizeof(temp));
}
int main() {
    ios::sync_with_stdio(false);
    //freopen("Quad Tiling.in","r",stdin);
    while(cin>>n>>m){
        if(!n&&!m) break;
        init(); 
        if(n<=4){
            cout<>=1;
        }
        cout<

POJ 3735: Training little cats
题解链接:https://blog.csdn.net/wangjian8006/article/details/7884989
代码如下

/*
题解链接:https://blog.csdn.net/wangjian8006/article/details/7884989 
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=100+5;
const int INF=0x3f3f3f3f;
int n,k,p;
ll m,f[maxn],e[maxn][maxn]; //e为系数矩阵 
void pre(){
    memset(e,0,sizeof(e));
    memset(f,0,sizeof(f));
    for(int i=1;i<=p;i++) e[i][i]=1;
    f[p]=1;
}
void mul(ll b[maxn][maxn],ll a[maxn]){
    ll temp[maxn]={0};
    for(int i=1;i<=p;i++) for(int j=1;j<=p;j++) temp[i]+=b[i][j]*a[j];
    memcpy(a,temp,sizeof(temp));
}
void mulself(ll a[maxn][maxn],ll b[maxn][maxn]){
    ll temp[maxn][maxn]={0};
    //if 判断是稀疏矩阵的优化,注意循环的顺序 
    for(int i=1;i<=p;i++) for(int k=1;k<=p;k++) if(a[i][k]) for(int j=1;j<=p;j++) temp[i][j]+=a[i][k]*b[k][j];
    memcpy(a,temp,sizeof(temp));
}
int main() {
    ios::sync_with_stdio(false);
    //freopen("Training little cats.in","r",stdin);
    while(cin>>n>>m>>k){
        if(!n&&!m&&!k) break;
        p=n+1; //p is the size of matrix
        pre();
        char ch;
        while(k--){
            getchar(); //enter
            cin>>ch;
            int pos,p1,p2;
            if(ch=='g'){ //get
                cin>>pos;
                e[pos][p]++;
            }
            if(ch=='e'){ //eat
                cin>>pos;
                for(int i=1;i<=p;i++) e[pos][i]=0;
            }
            if(ch=='s'){ //swap
                cin>>p1>>p2;
                for(int i=1;i<=p;i++) swap(e[p1][i],e[p2][i]);
            }
        }
        /*
        for(int i=1;i<=p;i++){
            for(int j=1;j<=p;j++){
                cout<>=1;
        }
        for(int i=1;i<=n;i++) cout<

数据结构与DP

POJ 3171: Cleaning Shifts
算法竞赛进阶指南上的题目,也是挑战程序设计竞赛上面的题目。
表示覆盖的最小代价。
先按照右端点升序排序,顺序考虑每个区间。
初值:,其余为INF
目标:,其中
转移方程:,其中
ps:按照左端点升序排序来做也可行,目前原因未知。
代码如下

/*
算法竞赛进阶指南上的题目,也是挑战程序设计竞赛上面的题目。
d[i]表示覆盖[M,i]的最小代价。
先按照右端点升序排序,顺序考虑每个区间。
初值:d[m-1]=0,其余为INF 
目标:max{d[x]},其中x>=b_{i}
转移方程:d[b_{i}]=min{d[x]}+S_{i},其中a_{i}-1<=x<=b_{i} 
ps:按照左端点升序排序来做也可行,目前原因未知。 
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define D(x) cout<<#x<<" = "<pii;
const int maxn=10000+5;
const int maxL=86399+5;
const int INF=0x3f3f3f3f;
struct node {
    int x,y,s;
    bool operator<(const node &h)const {
        return (y>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    tr[rt].dat=min(tr[rt<<1].dat,tr[rt<<1|1].dat);
}
void change(int rt,int pos,int v){
    if(tr[rt].l==tr[rt].r){
        tr[rt].dat=min(v,tr[rt].dat);
        return;
    }
    int mid=tr[rt].l+tr[rt].r>>1;
    if(pos<=mid) change(rt<<1,pos,v);
    else change(rt<<1|1,pos,v);
    tr[rt].dat=min(tr[rt<<1].dat,tr[rt<<1|1].dat);
}
int ask(int rt,int l,int r){
    if(tr[rt].l>=l&&tr[rt].r<=r) return tr[rt].dat;
    int mid=tr[rt].l+tr[rt].r>>1;
    int val=INF;
    if(mid>=l) val=min(val,ask(rt<<1,l,r));
    if(mid>n>>m>>e;
    for(int i=1; i<=n; i++) cin>>seq[i].x>>seq[i].y>>seq[i].s;
    sort(seq+1,seq+n+1);
    build(1,m-1,e); //这边只需要建立到e就可以了 因为如果change(1,seq[i].y,val+seq[i].s)中seq[i].y>e,会更新到e上,也算做合法 
    change(1,m-1,0);//f[m-1]=0
    for(int i=1;i<=n;i++){
        if(seq[i].y=e) ans=min(ans,ask(1,e,seq[i].y));
    }
    ans==INF?cout<<-1:cout<

你可能感兴趣的:(动态规划(二))