HDU 5348 MZL's endless loop(DFS+邻接表)

MZL's endless loop

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Special Judge

Problem Description
As we all kown, MZL hates the endless loop deeply, and he commands you to solve this problem to end the loop.
You are given an undirected graph with  n  vertexs and  m  edges. Please direct all the edges so that for every vertex in the graph the inequation  |out degree  in degree|1  is satisified.
The graph you are given maybe contains self loops or multiple edges.
 

Input
The first line of the input is a single integer  T , indicating the number of testcases.
For each test case, the first line contains two integers  n  and  m .
And the next  m  lines, each line contains two integers  ui  and  vi , which describe an edge of the graph.
T100 1n105 1m3105 n2105 m7105 .
 

Output
For each test case, if there is no solution, print a single line with  1 , otherwise output  m  lines,.
In  i th line contains a integer  1  or  0 1  for direct the  i th edge to  uivi 0  for  uivi .
 

Sample Input
  
  
2 3 3 1 2 2 3 3 1 7 6 1 2 1 3 1 4 1 5 1 6 1 7
 

Sample Output
  
  
1 1 1 0 1 0 1 0 1
 

Source
 

/*****************************************************************/

题意:一个具有n个结点,m条无向边的无向图,要求我们规定每条边的方向,使其成为有向图之后每个结点的入度与出度差的绝对值小于1,若无解,则输出-1

解题思路:该题的解法有很多种,有用欧拉路的,也有用搜索的,而我要讲的方法就是深搜

首先我们先看看多校题解报告中的思路


出题人的想法是一张图中除了环就是树,根据左孝凌版离散数学中树的定义“无回路的连通图”可以得出这样一个结论,要么有回路(环),要么没有回路(树),无外乎这么两种情况,所以根据环与树各自的属性特点,此题从每个点开始DFS这张图就好了

下面给出我做此题时的思路

首先暂且先不考虑环还是树,直接进行深搜,对每个点进行出度和入度的判断,如果出度大,就先进行反向的搜索(每搜索一条边u,v就认为这是一条从v到u的有向边),如果入度大,进行正向搜索(每搜到一条边u,v认为这是一条从u到v的有向边),一直搜索到找不到边能继续为止。

注意:

①已经使用过的边为了防止再次被遍历到,可以修改head[u]的值,即head[u] = edge[i].next

②注意自环,因为能否继续向下层搜索是根据v的入度和出度大小来决定的,但是如果是自环的话可能会影响继续搜索。

另外,此题不存在无解的可能

反证法证明假设存在一个结点v,满足该结点的入度比出度多2,那么,当有一条边搜索到v后找不到后继,导致v的入度比出度多1,这时又有一条边搜索到v,导致v的入度比出度多2,但是这样的话就会与第一条找不到后继的情况冲突,所以不会出现入度比出度多2的情况,其余情况亦是如此,所以不会有无解的结果。

闲话不多说,上AC代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 100005;
const int inf = 1000000000;
struct node
{
    int to,next;
}edge[6*N];
int k,head[N],num[N],in[N],out[N],n,ans[N*3];
bool vis[N*6];
void add_edge(int from,int to)
{
    edge[k].to=to;
    edge[k].next=head[from];
    head[from]=k++;
}
void DFS1(int u)
{
    int i,v;
    for(i=head[u];i+1;i=edge[i].next)
    {
        if(vis[i])
        {
            head[u]=edge[i].next;
            continue;
        }
        v=edge[i].to;
        if(u!=v&&in[v]>out[v])
            continue;
        out[u]++;
        in[v]++;
        vis[i]=vis[i^1]=true;
        ans[i/2]=i%2?0:1;
        head[u]=edge[i].next;
        DFS1(v);
        break;
    }
}
void DFS2(int u)
{
    int i,v;
    for(i=head[u];i+1;i=edge[i].next)
    {
        if(vis[i])
        {
            head[u]=edge[i].next;
            continue;
        }
        v=edge[i].to;
        if(u!=v&&in[v]<out[v])
            continue;
        out[v]++;
        in[u]++;
        vis[i]=vis[i^1]=true;
        ans[i/2]=i%2?1:0;
        head[u]=edge[i].next;
        DFS2(v);
        break;
    }
}
int main()
{
    int t,m,i,u,v;
    scanf("%d",&t);
    while(t--)
    {
        k=0;
        memset(head,-1,sizeof(head));
        memset(num,0,sizeof(num));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(vis,false,sizeof(vis));
        scanf("%d%d",&n,&m);
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            add_edge(u,v);
            add_edge(v,u);
            num[u]++;
            num[v]++;
        }
        for(i=1;i<=n;i++)
            while(in[i]+out[i]<num[i])
                if(in[i]>=out[i])
                    DFS1(i);
                else
                    DFS2(i);
        for(i=0;i<m;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

菜鸟成长记

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值