zoj-3777-Problem Arrangement(状态压缩DP)

来源:互联网 发布:美利坚淘宝之王 编辑:程序博客网 时间:2024/04/29 03:18

思路来源:http://blog.csdn.net/u013081425/article/details/23677585

                 http://blog.csdn.net/fulongxu/article/details/23737797

粗略分析一下:为什么这种状态压缩能减少时间运行:

方法1主要3层循环,时间复杂度有(1<<n)*n*M,对应N=12最大时考虑 (1<<12) * 12 * 500 约等于2400万次

方法2枚举遍历,     时间复杂度有 n! .              对应N=12为 12!  为479001600      约等于47900万次,可见二者此时 时间上可有20倍差距!

方法1:(状态压缩DP)

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<vector>#include<list>#include<stack>#include<queue>#include<string>#include<algorithm>using namespace std;int gys(int a,int b){    int r;    if(a<b){r=a;a=b;b=r;}    while(b!=0){        r =a %b;        a=b;        b=r;    }    return a;}int DP[(1<<12)+5][500+5];int P[12+1][12+1];int factorial[12+1]={1};int main(){#ifndef ONLINE_JUDGE    freopen("testCase.txt","r",stdin);#endif    int T,N,M;    for(int i=1;i<=12;i++)        factorial[i]=factorial[i-1]*i;    //cin>>T;    scanf("%d",&T);    while(T--){        memset(DP,0,sizeof(DP));        //cin>>N>>M;        scanf("%d %d",&N,&M);        for(int i=0;i<N;i++)            for(int j=0;j<N;j++)                //cin>>P[i][j];                scanf("%d",&P[i][j]);        DP[0][0] = 1;        for(int i=0;i<((1<<N)-1);i++){            int cnt=0;            for(int j=0;j<N;j++){                if(i&(1<<j))                    cnt++;            }            for(int j=0;j<N;j++){                if((i&(1<<j)) == 0){                    for(int k=0;k<=M;k++){                        int y= (k+ P[cnt][j]) <= M?(k+P[cnt][j]):M;                        DP[i+(1<<j)][y] += DP[i][k];                    }                }            }        }        if(DP[(1<<N)-1][M]==0)            printf("No solution\n");        else{            int a= DP[(1<<N)-1][M];            int b= factorial[N];            int divid = gys(DP[(1<<N)-1][M],factorial[N]);            a /= divid;            b /= divid;            printf("%d/%d\n",b,a);        }    }    return 0;}


方法2:(枚举遍历,通不过OJ测试)

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<vector>#include<list>#include<stack>#include<queue>#include<string>#include<algorithm>using namespace std;int P[12*12]; //P[12][12]int T;int N,M;void swap(int *a ,int *b){int m ;m = *a;*a = *b;*b = m;} int n= 0;int accum = 0; // >M 累加void perm(int list[],int k, int m ){int i;    int index =0;    int total = 0;if(k > m){for(i = 0 ; i <= m ; i++){//cout<<"r"<<list[i];            index = list[i];            total += P[i*N+index];             }        if(total >=M)            accum++;//cout<<"/n";n++;}else{for(i = k ; i <=m;i++){swap(&list[k],&list[i]);perm(list,k+1,m);swap(&list[k],&list[i]);}}}int gys(int a,int b){    int r;    if(a<b){r=a;a=b;b=r;}    while(b!=0){        r =a %b;        a=b;        b=r;    }    return a;}int pos[12];int main(){#ifndef ONLINE_JUDGE    freopen("testCase.txt","r",stdin);#endif    //cin>>T;    scanf("%d",&T);    while(T--){        n = 0;        accum = 0;        //cin>>N>>M;        scanf("%d %d",&N,&M);        for(int i=0;i<N*N;i++){            scanf("%d",&P[i]);        }        for(int i =0;i<N;i++)            pos[i] = i;        perm(pos,0,N-1);        //cout<< accum<<' '<< n<<endl;                if(accum ==0)            printf("No solution\n");        else{            int divid = gys(accum,n);            accum /= divid;            n /= divid;            printf("%d/%d\n",n,accum);        }    }    return 0;}


 

 

0 0
原创粉丝点击