传送门:【ACDream】1409 Musical Andrew Stankevich Contest 21
题目分析:我已经不想吐嘈了。。。。。这道模拟整死我了。。。
各种数组,各种注释。。。如果没有注释我怕还写不出来。。
题目很简单,,就是调的很辛苦T U T
就是简单状压DP+恶心的模拟。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = a ; i < b ; ++ i ) #define For( i , a , b ) for ( int i = a ; i <= b ; ++ i ) #define rev( i , a , b ) for ( int i = a ; i >= b ; -- i ) #define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next ) #define clr( a , x ) memset ( a , x , sizeof a ) #define cpy( a , x ) memcpy ( a , x , sizeof a ) const int MAXN = 11 ; struct Pre { int S , idx ; } pre[1 << MAXN][MAXN] ;//前驱 int city[MAXN][3] ;//每个城市的每种人的人数 int G[MAXN][MAXN] ;//G[u][v] = 1表示u,v之间存在边 int vis[MAXN][MAXN][MAXN] ;//前i天第j个城市第k个乐队是否表演过。 int perform[MAXN][MAXN][MAXN] ;//第i天第j个城市第k个乐队是有表演。 int sum[MAXN][MAXN][MAXN] ;//前i天第j个城市周围的城市被第k个乐队表演过的数目。 int in[MAXN][MAXN] ;//第i天第j个城市有多少个乐队有表演 int all[MAXN][MAXN] ;//第i天第j个城市及周围有多少个乐队有表演 double dp[1 << MAXN][MAXN] ; int n , m , K , tot ; void clear () { tot = 1 << n ; clr ( G , 0 ) ; clr ( in , 0 ) ; clr ( all , 0 ) ; clr ( vis , 0 ) ; clr ( pre , -1 ) ; clr ( sum , 0 ) ; clr ( perform , 0 ) ; rep ( i , 0 , tot ) rep ( j , 0 , n ) dp[i][j] = -1 ; } int count ( int x ) { return x ? count ( x >> 1 ) + ( x & 1 ) : 0 ; } void print ( int S , int idx ) { if ( pre[S][idx].idx != -1 ) print ( pre[S][idx].S , pre[S][idx].idx ) ; printf ( "%d%c" , idx + 1 , S == tot - 1 ? '\n' : ' ' ) ; } void solve () { clear () ; rep ( i , 0 , n ) rep ( j , 0 , 3 ) scanf ( "%d" , &city[i][j] ) ; rep ( i , 0 , n ) G[i][i] = 1 ; rep ( i , 0 , m ) { int u , v ; scanf ( "%d%d" , &u , &v ) ; -- u ; -- v ; G[u][v] = G[v][u] = 1 ; } rep ( k , 0 , K ) rep ( i , 0 , n ) { int x ; scanf ( "%d" , &x ) ; -- x ; vis[i][x][k] = 1 ; perform[i][x][k] = 1 ; in[i][x] ++ ; } rep ( i , 1 , n ) rep ( j , 0 , n ) rep ( k , 0 , K ) vis[i][j][k] |= vis[i - 1][j][k] ; rep ( i , 0 , n ) rep ( j , 0 , n ) rep ( k , 0 , K ) { rep ( l , 0 , n ) if ( G[j][l] && j != l ) { sum[i][j][k] += vis[i][l][k] ; } } rep ( i , 0 , n ) rep ( j , 0 , n ) rep ( l , 0 , n ) if ( G[j][l] ) all[i][j] += in[i][l] ; rep ( i , 0 , n ) { double tmp = 0 ; tmp += ( double ) city[i][0] / ( in[0][i] + 1 ) ;//第一类 tmp += ( double ) city[i][1] / ( in[0][i] + 1 ) * 7 ;//第二类 rep ( j , 0 , n ) if ( G[i][j] ) tmp += ( double ) city[j][2] / ( all[0][j] + 1 ) * 7 ;//第三类 dp[1 << i][i] = tmp ; } rep ( S , 0 , tot ) { int now = count ( S ) - 1 ;//当前状态个数-1为当前星期 int next = now + 1 ;//下一星期 rep ( i , 0 , n ) if ( dp[S][i] >= 0 ) {//状态dp[S][i]存在 rep ( j , 0 , n ) { if ( S & ( 1 << j ) ) continue ;//已经走过j了,跳过 double tmp = 0 ; //第一种人 int cnt = 0 , maxv = -1 ; rep ( k , 0 , K ) if ( perform[next][j][k] ) { if ( sum[now][j][k] > maxv ) { cnt = 1 ; maxv = sum[now][j][k] ; } else if ( sum[now][j][k] == maxv ) ++ cnt ; } int cnt2 = 0 ; rep ( l , 0 , n ) if ( S & ( 1 << l ) ) if ( G[j][l] ) ++ cnt2 ; if ( cnt2 > maxv ) tmp += city[j][0] ; else if ( cnt2 == maxv ) tmp += ( double ) city[j][0] / ( cnt + 1 ) ; //第二种人 tmp += ( double ) city[j][1] / ( in[next][j] + 1 ) * 7 ; //第三种人 rep ( l , 0 , n ) if ( G[j][l] ) tmp += ( double ) city[l][2] / ( all[next][l] + 1 ) * 7 ; //统计 if ( tmp + dp[S][i] > dp[S | ( 1 << j )][j] ) { dp[S | ( 1 << j )][j] = tmp + dp[S][i] ; pre[S | ( 1 << j )][j].S = S ; pre[S | ( 1 << j )][j].idx = i ; } } } } double ans = 0 ; int idx = 0 ; rep ( i , 0 , n ) if ( ans < dp[tot - 1][i] ) { ans = dp[tot - 1][i] ; idx = i ; } printf ( "%.10f\n" , ans ) ; print ( tot - 1 , idx ) ; } int main () { while ( ~scanf ( "%d%d%d" , &n , &m , &K ) ) solve () ; return 0 ; }