acdream 1409 Musical 状压DP
链接:http://acdream.info/problem?
题意:整个国家有n座城市,每座城市有三种粉丝。
第一种一周看一场音乐剧,挑选的音乐剧是已经在周围城市播放上演过的次数最多的音乐剧中的随机一个。
另外一种每天看一场音乐剧,挑选的是在本城市上映的音乐剧中的随机一个。
第三种每天看一场音乐剧,挑选的是在本城市以及周围城市中上映的音乐剧中的随机一个。
周围的城市是指这座城市与当前城市之间存在路径。
我如今要带着一部音乐剧环游全国(能够坐飞机,不用走路径),每座城市呆一周,而且还存在其它m座城市在这n周内绕国上映(也可能放假),问我这个音乐剧所能吸引到的粉丝的总数的期望是多少。
思路:首先要模拟找出每座城市每周的上映音乐剧数量。每座城市每周周围的上映的音乐剧数,每一个音乐剧在每周每座城市内存在的信息数。
然后用状态压缩,dp[i][j]表示第i周状态为j的条件下能吸引到的粉丝总数。
这题比較繁琐。模拟过程比較蛋疼。
代码:
#include <algorithm> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <ctype.h> #include <iostream> #include <map> #include <queue> #include <set> #include <stack> #include <string> #include <vector> #define eps 1e-8 #define INF 0x7fffffff #define PI acos(-1.0) #define seed 31//131,1313 //#define LOCAL typedef long long LL; typedef unsigned long long ULL; using namespace std; double city[15][5]; bool vis[15][15][15];//音乐剧,周,城市 bool now[15][15][15]; int V[15][15]; int top[15]; int aa[15][15][15];//音乐剧,周。城市的信息数 int ans[15]; int road[15]; int Pow[15]; int cc[15][15];//周,城市的上映音乐剧数 int dd[15][15];//周,相邻以及本身上映的音乐剧数 double dp[15][1500]; int p[15][1500]; void init() { Pow[0]=1; for(int i=1; i<=10; i++) Pow[i]=Pow[i-1]*2; return ; } int main() { init(); int n,m,kk,c; scanf("%d%d%d",&n,&m,&kk); for(int i=0; i<n; i++) scanf("%lf%lf%lf",&city[i][0],&city[i][1],&city[i][2]); for(int i=1; i<=m; i++) { int u,v; scanf("%d%d",&u,&v); V[u-1][top[u-1]++]=v-1; V[v-1][top[v-1]++]=u-1; } for(int i=1; i<=kk; i++)//剧 { for(int j=1; j<=n; j++)//周 { scanf("%d",&c); c--; if(j!=1) for(int k=0; k<n; k++) vis[i][j][k]=vis[i][j-1][k]; vis[i][j][c]=1; now[i][j][c]=1; cc[j][c]++; dd[j][c]++; for(int k=0; k<top[c]; k++) dd[j][V[c][k]]++; } } for(int i=1; i<=kk; i++) //音乐剧 for(int j=1; j<=n; j++) //周 for(int k=0; k<n; k++) //城市 for(int l=0; l<top[k]; l++) { if(vis[i][j][V[k][l]]) aa[i][j][k]++; } int mos=(1<<n); for(int i=0; i<=n; i++) for(int j=0; j<mos; j++) dp[i][j]=-1; dp[0][0]=0; for(int i=1; i<=n; i++)//周 { for(int j=1; j<mos; j++)//状态 { for(int k=0; k<n; k++)//到的城市 { //cout<<k<<endl; int res=0; if(j-Pow[k]<0) break; if(dp[i-1][j-Pow[k]]!=-1) { for(int l=0; l<top[k]; l++) if(Pow[V[k][l]]&j) res++; int flag = 0; double tot = 0; for(int l=1; l<=kk; l++) { if(aa[l][i][k]>res&&now[l][i][k]) { flag = 1; break; } else if(aa[l][i][k]==res&&now[l][i][k]) tot++; } double all = 0; if(flag == 0) all+=city[k][0]/(tot+1); all+=city[k][1]*7/(cc[i][k]+1); all+=city[k][2]*7/(dd[i][k]+1); for(int ii=0; ii<top[k]; ii++) { int pos=V[k][ii]; all+=city[pos][2]*7/(dd[i][pos]+1); } if(all+dp[i-1][j-Pow[k]]>dp[i][j]) { dp[i][j]=all+dp[i-1][j-Pow[k]]; p[i][j]=k; } } } } } int nn=mos-1; int way[15],ttt=0; for(int i=n; i>=1; i--) { //cout<<p[i][nn]<<endl; way[ttt++]=p[i][nn]; nn-=Pow[p[i][nn]]; } printf("%.8lf\n",dp[n][mos-1]); for(int i=ttt-1;i>=0;i--) { if(i==ttt-1) printf("%d",way[i]+1); else printf(" %d",way[i]+1); } printf("\n"); return 0; }