HDU-6105 Gameia - 2017 Multi-University Training Contest - Team 6(思维之找规律或二分图最大匹配)
2017-08-11 23:59
489 查看
题意:
一棵1为根n个节点的树,Alice先手,Bob后手, Alice的操作是选一个未染色的点将其染成白色,Bob的操作是选一个未染色的点将其染成黑色,并且和这个点直接连边的点也被强制染成黑色(无论这些点之前是否有颜色),Bob还可以任意时刻切断k条边,当所有点都有颜色的时候,游戏结束,如果存在白色点Alice赢,否则Bob赢。
思路:
就暂且把所有的先手赢还是输都当作博弈吧...其实本题就是一个思维题,首先如果有奇数个顶点,Bob必输,画一下就知道了(每次都选择"叶子"节点的父亲节点染白色,Bob只能染该叶子节点,最终轮到Alice还会剩一个点)。当为偶数时,我是以所有顶点为根进行n次树的遍历,如果该根节点有>=2个奇数子树(不算该根节点),Bob必输(仍然是上述思路将两个奇数长度子树不断染色直至该子树剩余一个点,则造成Alice必胜),再否则就得判断Bob能否将该树切成若干个2-连通分支(就是死在这儿...只要能想到2-连通分支这点很容易推出k如果大于等于n/2-1,则能成功切割。唉,智障思维卡住愣是没想到),如果能则Bob必胜,否则Alice必胜。
代码:
其实问题仔细分析发现就是判可不可以将所有点分成若干个2-连通分支,所以就变成求二分图的最大匹配了,然后再判断k是否能够分割得了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 505;
vector<int> G[maxn];
int vis[maxn], match[maxn];
int n, k;
int dfs(int u)
{
for(int i = 0; i < G[u].size(); ++i)
{
int v = G[u][i];
if(vis[v]) continue;
vis[v] = 1;
if(match[v] == -1 || dfs(match[v]))
{
match[v] = u;
return 1;
}
}
return 0;
}
int main()
{
int t, u, ans;
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; ++i) G[i].clear();
memset(match, -1, sizeof match);
for(int i = 2; i <= n; ++i)
{
scanf("%d", &u);
G[i].push_back(u);
G[u].push_back(i);
}
ans = 0;
for(int i = 1; i <= n; ++i)
{
memset(vis, 0, sizeof vis);
if(dfs(i)) ++ans;
}
if(ans == n && k >= n/2-1) puts("Bob");
else puts("Alice");
}
return 0;
}
比完赛看题解恍然大悟的感觉贼鸡儿不爽,好多次都只差一点,很烦,继续加油~
一棵1为根n个节点的树,Alice先手,Bob后手, Alice的操作是选一个未染色的点将其染成白色,Bob的操作是选一个未染色的点将其染成黑色,并且和这个点直接连边的点也被强制染成黑色(无论这些点之前是否有颜色),Bob还可以任意时刻切断k条边,当所有点都有颜色的时候,游戏结束,如果存在白色点Alice赢,否则Bob赢。
思路:
就暂且把所有的先手赢还是输都当作博弈吧...其实本题就是一个思维题,首先如果有奇数个顶点,Bob必输,画一下就知道了(每次都选择"叶子"节点的父亲节点染白色,Bob只能染该叶子节点,最终轮到Alice还会剩一个点)。当为偶数时,我是以所有顶点为根进行n次树的遍历,如果该根节点有>=2个奇数子树(不算该根节点),Bob必输(仍然是上述思路将两个奇数长度子树不断染色直至该子树剩余一个点,则造成Alice必胜),再否则就得判断Bob能否将该树切成若干个2-连通分支(就是死在这儿...只要能想到2-连通分支这点很容易推出k如果大于等于n/2-1,则能成功切割。唉,智障思维卡住愣是没想到),如果能则Bob必胜,否则Alice必胜。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 505; struct node { int v, next; } edge[maxn*2]; int no, head[maxn]; int n, k; inline void init() { no = 0; memset(head, -1, sizeof head); } inline void add(int u, int v) { edge[no].v = v; edge[no].next = head[u]; head[u] = no++; } int dfs(int cur, int father) { int sum = 1; for(int k = head[cur]; k != -1; k = edge[k].next) { int v = edge[k].v; if(v == father) continue; sum += dfs(v, cur); } return sum; } int jg(int cur) { int now = 0; for(int k = head[cur]; k != -1; k = edge[k].next) { int v = edge[k].v; int t = dfs(v, cur); if(t&1) ++now; if(now >= 2) return -1; } return 1; } int main() { //freopen("in.txt", "r", stdin); int t, x, cnt; scanf("%d", &t); while(t--) { scanf("%d %d", &n, &k); ef59 init(); for(int i = 2; i <= n; ++i) { scanf("%d", &x); add(x, i), add(i, x); } if(n&1) {puts("Alice"); continue;} cnt = 0; for(int i = 1; i <= n; ++i) { cnt = jg(i); if(cnt == -1) break; } if(cnt == -1) puts("Alice"); else if(k-n/2+1 >= 0) puts("Bob"); else puts("Alice"); } return 0; }
其实问题仔细分析发现就是判可不可以将所有点分成若干个2-连通分支,所以就变成求二分图的最大匹配了,然后再判断k是否能够分割得了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 505;
vector<int> G[maxn];
int vis[maxn], match[maxn];
int n, k;
int dfs(int u)
{
for(int i = 0; i < G[u].size(); ++i)
{
int v = G[u][i];
if(vis[v]) continue;
vis[v] = 1;
if(match[v] == -1 || dfs(match[v]))
{
match[v] = u;
return 1;
}
}
return 0;
}
int main()
{
int t, u, ans;
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &n, &k);
for(int i = 1; i <= n; ++i) G[i].clear();
memset(match, -1, sizeof match);
for(int i = 2; i <= n; ++i)
{
scanf("%d", &u);
G[i].push_back(u);
G[u].push_back(i);
}
ans = 0;
for(int i = 1; i <= n; ++i)
{
memset(vis, 0, sizeof vis);
if(dfs(i)) ++ans;
}
if(ans == n && k >= n/2-1) puts("Bob");
else puts("Alice");
}
return 0;
}
比完赛看题解恍然大悟的感觉贼鸡儿不爽,好多次都只差一点,很烦,继续加油~
相关文章推荐
- HDU - 6105 Gameia(必胜策略)(2017 Multi-University Training Contest - Team 6)
- 2017 Multi-University Training Contest - Team 6 HDU 6105 Gameia(博弈)
- HDU 6105 - Gameia | 2017 Multi-University Training Contest 6
- 2017 Multi-University Training Contest - Team 1 1011&&HDU 6043 KazaQ's Socks【规律题,数学,水】
- HDU 6038 Function(找规律)——2017 Multi-University Training Contest - Team 1
- HDU-6058 Kanade's sum - 2017 Multi-University Training Contest - Team 3(思维+模拟链表)
- hdu 6038 找规律 置换 2017 Multi-University Training Contest - Team 1
- HDU 6127 Hard challenge(思维+计算几何)——2017 Multi-University Training Contest - Team 7
- HDU-6129 Just do it - 2017 Multi-University Training Contest - Team 7(规律、杨辉三角、组合数奇偶性)
- HDU-6060 RXD and dividing - 2017 Multi-University Training Contest - Team 3(思维+最小斯坦纳树)
- HDU-6140 Killer Names - 2017 Multi-University Training Contest - Team 8(思维)
- hdu 6045 简单的思维题 2017 Multi-University Training Contest - Team 2
- HDU 6055 Regular polygon(计算几何+思维)——2017 Multi-University Training Contest - Team 2
- HDU 6048 Puzzle(找规律)——2017 Multi-University Training Contest - Team 2
- 2017 Multi-University Training Contest - Team 2,HDU 6045 Is Derek lying?(思维水题)
- hdu 6069 Counting Divisors(约数个数)(2017 Multi-University Training Contest - Team 4 )
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- 2017 Multi-University Training Contest - Team 4-hdu 6071 Lazy Running
- hdu 6071 Lazy Running(优先队列+dijkstra)(2017 Multi-University Training Contest - Team 4)
- hdu 6073 Matching In Multiplication(2017 Multi-University Training Contest - Team 4 )