UVALive 6462
题目链接:
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4473
题意:
两个人轮流选包,包里有一些颜色。包选完后放到柜子里。
规定柜子里如果某种颜色的个数大于等于S个时,柜子里该颜色的个数减S,此轮该人得到一颗魔法石。该操作在每轮会自动进行到不能进行为止。得到魔法石后下一轮仍然由此人执行。
两人都拥有最优策略。
问先手的人减后手的人的魔法石数。
思路:
简单状压。
模拟的时候使劲T,原因是多加了一维状态dp[i][j],j = 0,1表示是Alice还是Bob,去掉就A了。
源码:
using namespace std;
int dp[1<<21];
int col[1<<21][11];
int cnt[100];
int data[100][100];
int G, B, S;
void dfs(int s, int p)
{
if(dp[s] != -inf) return;
if(s == ((1 << B) - 1)){
dp[s] = 0;
return;
}
for(int k = 0 ; k < B ; k++){
if((s & (1 << k)) == 0){
int ts = s | (1 << k);
for(int l = 0 ; l <= G ; l++)
col[ts][l] = col[s][l];
int val = 0;
for(int l = 1 ; l <= G ; l++){
col[ts][l] += data[k][l];
if(col[ts][l] >= S){
val++;
col[ts][l] %= S;
}
}
// printf(“i = %d, j = %d, val = %d, ts = %d, dp = %d\n”, i, j, val, ts, dp[i][j]);
if(val == 0){
dfs(ts, !p);
dp[s] = max(dp[s], -dp[ts]);
}
else{
dfs(ts, p);
dp[s] = max(dp[s], val + dp[ts]);
}
}
}
}
int main()
{
// freopen(“I.in”, “r”, stdin);
while(scanf(“%d%d%d”, &G, &B, &S) != EOF && G + B + S){
if(B == 0){
printf(“%d\n”, 0);
continue;
}
int sum = 0;
memset(data, 0, sizeof(data));
for(int i = 0 ; i < B ; i++){
scanf(“%d”, &cnt[i]);
sum += cnt[i];
int u;
for(int j = 0 ; j < cnt[i] ; j++) scanf(“%d”, &u), data[i][u]++;
}
for(int i = 0 ; i < (1 << B) ; i++)
dp[i] = -inf;
memset(col, 0, sizeof(col));
dfs(0, 0);
// for(int i = 0 ; i < (1 << B) ; i++)
// for(int j = 0 ; j < 2 ; j++)
// printf(“dp[%d][%d] = %d\n”, i, j, dp[i][j]);
// for(int i = 0 ; i < (1 << B) ; i++){
// printf(“color “);
// for(int j = 1 ; j <= G ; j++)
// printf(“%d “, col[i][j]);
// printf(“\n”);
// }
int ans = dp[0];
// if(dp[(1<