题目链接:http://poj.org/problem?id=3710
题意:
(1)有若干个个局部联通的图;
(2)Harry 和Sally轮流从图中删边,删去一条边后,不与根节点相连的部分将被移走。Sally为先手。
(3) 图是通过从基础树中加一些边得到的。 所有形成的环保证不共用边,且只与基础树有一个公共点。
(4)谁无路可走谁输。
思路:结论
因此去掉所有的偶环,将所有的奇环变为长度为1的链。那么剩下的问题就是树(在这里就是无向图)的判环问题。对于某一个节点,若其连着一个即偶数的环,那么显然这个换是不用计算的,所以要标记一下。u连着一个奇数环的话要要标记奇数环中与u紧邻的一个要遍历。
const int MAX=105;
struct node
{
int v,next;
};
node edges[MAX*MAX];
int visit[MAX],head[MAX],e;
int dfn[MAX],low[MAX],color[MAX];
int n,m,id,colornum;
int stack[MAX],top;
int flag[MAX],SG[MAX];
int g[MAX][MAX];
void DFS(int u,int p)
{
dfn[u]=low[u]=++id;
visit[u]=1;
stack[top++]=u;
int i,v,temp;
for(i=head[u];i!=-1;i=edges[i].next)
{
v=edges[i].v;
if(v==p&&g[u][v]>1)
{
flag[u]=1;
continue;
}
if(!dfn[v])
{
DFS(v,u);
low[u]=min(low[u],low[v]);
}
else if(visit[v]==1&&v!=p)
{
low[u]=min(low[u],dfn[v]);
}
}
visit[u]=2;
if(dfn[u]==low[u])
{
temp=0;
while(stack[--top]!=u) flag[stack[top]]=1,temp++;
if(temp&&temp%2==0) flag[stack[top+1]]=0;
}
}
void Tarjan()
{
memset(dfn,0,sizeof(dfn));
memset(visit,0,sizeof(visit));
id=0;top=0;
DFS(1,-1);
}
void Add(int u,int v)
{
edges[e].v=v;
edges[e].next=head[u];
head[u]=e++;
}
void cal(int u)
{
flag[u]=1;
for(int i=head[u];i!=-1;i=edges[i].next)
{
int v=edges[i].v;
if(!flag[v]) cal(v),SG[u]^=SG[v]+1;
}
}
int C;
int main()
{
while(scanf("%d",&C)!=-1)
{
int ans=0,u,v;
while(C--)
{
scanf("%d%d",&n,&m);
memset(g,0,sizeof(g));
memset(SG,0,sizeof(SG));
memset(flag,0,sizeof(flag));
memset(head,-1,sizeof(head));
e=0;
while(m--)
{
scanf("%d%d",&u,&v);
Add(u,v);
Add(v,u);
g[u][v]++;
g[v][u]++;
}
Tarjan();
cal(1);
ans^=SG[1];
}
puts(ans?"Sally":"Harry");
}
return 0;
}