您的位置:首页 > 大数据 > 人工智能

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必胜。

代码:

#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;
}

比完赛看题解恍然大悟的感觉贼鸡儿不爽,好多次都只差一点,很烦,继续加油~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐