T1 做任务
题目描述
现有一款游戏,你作为玩家,拥有k种物品。开始时,每种物品有1000件。
现在,在你面前有n个任务,每种任务都可能消耗一些物品,也可能得到一些物品。做第i个任务的物品得失情况用一个包含k个字母的字符串Si表示,其中每个字母都是+,-,/中的一种,第j个字母表示该任务对物品j的数量的影响。+表示做这个任务能得到一个物品j,-表示做这个任务会消耗一个物品j,/表示做这个任务对物品j的数量不产生影响。
但是,做任务是有前提条件的。游戏设计者约定了m个限制关系,每个限制关系是一个有序数对(i, j),表示做任务i前必须先做任务j。
现在,你需要选择性的做一些任务,使得获得的物品最多。
比较两种方案的获得的物品数的方法如下:先比较他们获得第物品1的个数,若相同,再比较物品2,若相同,再比较物品3,以此类推。
Input
第一行有三个整数n,m,k
接下来的n行,每行有一个字符串,第i行的字符串表示Si
接下来的m行,每行有两个整数i,j表示限制关系
Output
输出包含一行,k个空格分隔的整数,表示做完你选的任务之后每种物品的拥有量。
Sample Input
3 3 2
+-
+/
-+
2 1
2 3
3 1
Sample Output
1001 1000
Constraints
有20%的数据,n ≤ 10, k = 1
另有20%的数据,m = 0。
另有20%的数据,限制关系是一条链(m = n-1且所有i各不相同,所有j各不相同)。
另有20%的数据,限制关系是一棵树(m = n-1且所有i各不相同)。
100%的数据,n≤1000, k≤5, m≤5000,保证限制关系不会有环。
时间限制:1S
内存限制:512M
考试时的思路
分类讨论,前80pts
- n <= 10 二进制枚举暴力
- m = 0 无限制条件,直接贪心选第一位为+的,然后在第一位不变的情况下选第二位为+的,依次找下去,当然也可以排序
- m = n - 1 当成是树来做,将没有被限制的点作为根,然后记dp[i]表示以i为根子树中选一些方案的最优解,每次先递归处理子树,然后考虑要不要加入这棵子树,最后再和全0做一次比较
以上为80pts的思路
[Code]
#include<bits/stdc++.h> using namespace std; #define N 2050 #define M 10050 int read(){ int x=0; char c=getchar(); int flag=1; while(!isdigit(c)) { if(c=='-') flag=-1; c=getchar(); } while(isdigit(c)) { x=((x+(x<<2))<<1)+(c^48); c=getchar(); } return x*flag; } int n,m,k; int a[N][6]; struct Edge{ int to,next; }edge[M]; struct EDGE{ int u,v; bool tag; }e[M]; int head[N]; int tmp; int rd[N]; void add(int x,int y){ ++ tmp; ++ rd[y]; edge[tmp].to = y; edge[tmp].next = head[x]; head[x] = tmp; e[tmp].u = x; e[tmp].v = y; e[tmp].tag = 0; } void Add(int x,int y){ ++ tmp; ++ rd[y]; edge[tmp].to = y; edge[tmp].next = head[x]; head[x] = tmp; } namespace Task1{ int ans[6],tmp[6]; void work(){ for(int i = 1; i <= k; ++ i) ans[i] = 1000; for(int i = 0; i < (1 << n); ++ i){ bool flag = 1; for(int j = 1; j <= n; ++ j){ if(!(i & (1 << (j - 1)))){ for(int p = head[j]; p != -1; p = edge[p].next){ int t=edge[p].to; if(i & (1 << (t - 1))) { flag = 0; break ;} } } if(!flag) break; } if(!flag) continue; //printf("OK = %d\n",i); for(int j = 1; j <= k; ++ j) tmp[j] = 1000; for(int j = 1; j <= n; ++ j) if(i & (1 << (j - 1)) ) { for(int p = 1; p <= k; ++ p) tmp[p] += a[j][p]; } flag = 0; for(int p = 1; p <= k; ++ p) if(tmp[p] > ans[p]) { flag = 1; break; } else if(tmp[p] < ans[p]) break; if(flag){ //printf("MORE %d\n",i); for(int p = 1; p <= k; ++ p) ans[p] = tmp[p]; } } for(int i = 1; i <= k; ++ i) printf("%d ",ans[i]); puts(""); } } namespace Task2{ int ans[6]; void work(){ for(int i = 1; i <= k; ++ i) ans[i] = 1000; for(int i = 1; i <= n; ++ i){ bool flag = 1; for(int j = 1; j <= k; ++ j){ if(a[i][j] == 0) continue; if(a[i][j] < 0) flag = 0; break; } if(flag){ for(int j = 1; j <= k; ++ j) ans[j] += a[i][j]; } } for(int i = 1; i <= k; ++ i) printf("%d ",ans[i]); puts(""); } } namespace Task3{ int g[N][6]; void dfs(int nod){ for(int i = 1; i <= k; ++ i) g[nod][i] = a[nod][i]; for(int i = head[nod]; i != -1; i = edge[i].next){ int t = edge[i].to; dfs(t); bool flag = 1; for(int j = 1; j <= k; ++ j) { if(g[t][j] == 0) continue; if(g[t][j] < 0) flag = 0; break; } if(flag) { for(int j = 1; j <= k; ++ j) g[nod][j] += g[t][j]; } } bool flag = 1; for(int i = 1; i <= k; ++ i){ if(g[nod][i] == 0) continue; if(g[nod][i] < 0) flag = 0; break; } if(!flag) { for(int i = 1; i <= k; ++ i) g[nod][i] = 0; } } void work(){ int root; for(int i = 1; i <= n; ++ i) if(!rd[i]) { root = i; break; } dfs(root); for(int i = 1; i <= k; ++ i) printf("%d ",g[root][i] + 1000); puts(""); } } signed main(){ memset(head, -1, sizeof(head)); n = read(), m = read(), k = read(); for(int i = 1; i <= n; ++ i){ char s[10]; scanf("%s",s); for(int j = 1; j <= k; ++ j) if(s[j - 1] == '+') a[i][j] = 1; else if(s[j - 1] == '-') a[i][j] = -1; } for(int i = 1; i <= m; ++ i){ int x = read(), y = read(); add(y,x); } if(n <= 10) { Task1::work(); return 0; } if(m == 0) { Task2::work(); return 0; } if(m == n - 1) { Task3::work(); return 0; } return 0; } //Still WA
正解
考虑一个任务的奖励很像k位数,所以将其转化成10进制数,然后权值有正有负,考虑对于限制关系建图,方式就是如果做任务i之前需要做任务j,那就从i向j连一条边,然后对于这个图求最大权闭合子图.选出的子图就是答案.
首先最大权闭合子图是用所有正权值之和减去原图的最小割,然后我们相对于限制反向建边,就是要求如果要选一个点,则它之前的所有点必须要选.这样就满足了限制.
来源:https://www.cnblogs.com/zzhzzh123/p/12253732.html