思路来源: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;
}