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

2017 Multi-University Training Contest - Team 9:FFF at Valentine

2017-08-23 11:14 537 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6165

题目意思:FFF的牢房是一个n个节点m条边的有向图,图无自环,一对情侣被FFF关了起来

(二者关在哪里不知道,且不关在同一个点)。假如一个在点u一个在点v,能从点u到点v或

者能从点v到点u,则情侣就可以获救。即情侣双方任意一方能到达伴侣关押的位置,他们两个

就能获救。所以我们现在就要判断一个图,是否对于图中任意的点u-v都要存在u->v或v->u.

官方题解:缩点为DAG,则如果在拓扑序中出现了有两个及以上入度为0的点则不合法

昨天比赛的时候,我先用强连通缩点,然后跑DFS,然后WA掉了,今天再看,发现自己

1忘记判图的连通性,2就是dfs搜索的方法不太对。昨天又改了缩完点后,判断新图存不存

再欧拉通路,这个带判断图的连通性了,结果还WA,奔溃。现在没想出哪有错,感觉思路

也没错,假如图连通,缩点后图还连通,选择度为0的节点,开始然后把图中点串成一长串。

PS:队友写最短路解法,我写强连通缩点,最后都没过,真心弱啊。

解题思路:

首先对图进行缩点,对于一个图,对于一个连通分量来说,其内部所有的点都是可以相互到

达的,所以先用强连通缩点去环,并将一个环内的点进行统一的编号(即缩点)。对于一个

有向图,如果连通分量个数是1,那么这个图就是强连通的,则一定能够获救。否则我们构建

新的图,并统计节点的入度,首先入度为0的点只能有1个,超过一个的话,说明图本身不连通,

并且比较容易想到这个唯一的入度为0的点是我们dfs的起点,从这个点如果能把新图中的点

串成一个线性的长串,则情侣能够获救。所以我们要求dfs的最大深度,只有最大深度等于新

图中的节点个数的时候,才能说明从起点把图中的点串成了一长串,否则串不成一长串,情侣

也不能获救。

#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;

const int maxn = 2000;
const int maxm = 10000;

struct Edge
{
int u,v,nex;
}edge[maxm];
int head[maxm];   ///链表头节点
bool inStack[maxn];   ///标记是否在栈中
int Stack[maxn];      ///自写栈
int belong[maxn];     ///各个顶点属于那些连通分量
int dfn[maxn];        ///时间戳
int low[maxn];        ///u或u的子树能够追溯到的最早的栈中节点的序号
int in[maxn];         ///统计节点入度
int vis[maxn];
int cnt_edge,time,top,cnt,n,m,deepest;
///cnt_edge统计边数,time时间戳,top栈顶指针,cnt连通分量的个数,n节点数,m边数,deepest深搜最大深度
///加边函数
void addEdge(int u,int v)
{
edge[cnt_edge].u = u;
edge[cnt_edge].v = v;
edge[cnt_edge].nex = head[u];
head[u] = cnt_edge++;
}
///强连通缩点。
void tarjan(int u)
{
dfn[u] = low[u] = ++time;
Stack[++top] = u;
inStack[u] = true;
for(int i = head[u]; i != -1; i = edge[i].nex)
{
int v = edge[i].v;
if(!dfn[v])  ///没有被访问过
{
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(inStack[v])  ///在栈中
low[u] = min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
cnt++;
int temp;
do
{
temp = Stack[top--];
inStack[temp] = false;
belong[temp] = cnt;   ///节点temp属于第cnt个连通分量
}while(temp != u);
}
}
void solve()
{
top = time = cnt = 0;
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
for(int i = 1; i <= n; i++)
{
if(dfn[i]==0)
tarjan(i);
}
}
void dfs(int x,int depth)
{
vis[x] = 1;
deepest = max(depth,deepest);
for(int i = head[x]; i != -1; i = edge[i].nex)
{
int v = edge[i].v;
if(vis[v]==0)
{
dfs(v,depth+1);
vis[v] = 0;
}
}
}
int main()
{
int t,u,v;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
cnt_edge = 0;
for(int i = 1; i <= m; i++)
{
scanf("%d%d",&u,&v);
addEdge(u,v);
}
solve();         ///强连通缩点
if(cnt == 1)     ///整个图只有一个连通分量,则图强连通
{
printf("I love you my love and our love save us!\n");
}
else
{
///重建图
memset(in,0,sizeof(in));
memset(head,-1,sizeof(head));
int num = cnt_edge;
cnt_edge = 0;
for(int i = 0; i < num; i++)
{
u = edge[i].u;
v = edge[i].v;
int newu = belong[u];
int newv = belong[v];
if(newu != newv) ///两个点不在一个集合,即不在同一个环中,则建立关系
{
in[newv]++;
addEdge(newu,newv);
}
}
int start = 1,ccount = 0;
///ccount用来统计入度为0的点的个数
for(int i = 1; i <= cnt; i++)
{
if(in[i]==0)
{
start = i;
ccount++;
}
}
///入度为0的点最多1个,两个和两个以上说明图本身不连通。
if(ccount==1)
{
memset(vis,0,sizeof(vis));
deepest=0;
dfs(start,1);
}
if(ccount==1 && deepest==cnt)
printf("I love you my love and our love save us!\n");
else
printf("Light my fire!\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐