2015 多校赛 第五场 1006 (hdu 5348)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5348

 

题目大意:给出一幅无向图,问是否存在一种方案,使得给每条边赋予方向后,每个点的入度与出度之差小于等于1。如不存在,输出-1;存在,则按边的输入顺序输出方向。

比如:若给出第 m 条边为 u,v,则在对应第m行输出0表示u->v,输出1表示u<-v。

 

解题思路:

首先证明一定可以构造出符合要求的图。

对于一个环,显然可以使得其内的每个点入度与出度相等。之后可以把环看成点。

对于一棵树,则可以通过均分其子结点使得入度与出度之差小于等于1。

因此可以看作是把图分成由环和点构成的森林。则一定有解。

dfs遍历,首先遍历度数为奇数的点,因为这些点一定是起点或者终点。遍历完之后删去遍历过的边。

再遍历剩下的边。

代码中给ans[(id>>1)+1]的赋值,是因为每输入一条边,都向邻接表中加入两条有向边,因此边的本身序号 id 与在邻接表中的序号 id‘ 的关系为

id'>>1=id。这里 id' 为(0,1),(2,3)....因此直接除以2得到对应的序号。+1则只是为了使其在ans数组中从 1 开始储存。看个人习惯。

 

也算是被逼着学了下数组的邻接表用法。之前只会用vector的邻接表。

对结点 i ,head[i]表示以结点 i 为起点的最后一条加入的边,初始化为-1。

对边 j ,pre[j]表示与边 j 同起点的上一条边的编号,或者说再Edge数组中的序号;nxt[j]则表示同起点的下一条边的编号。

可以用to[j]表示边 j 的终点。也可以用结构体维护起点和终点的关系。

cost[j] 表示边 j 的边权。

 

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 200005
#define M 600005
struct edge{
    int u,v;
    edge(){}
    edge(int u,int v):u(u),v(v){}
}Edge[M];
int head[N],pre[M],nxt[M],du[N],ans[M>>1],E;
int n,m,t,a,b;
void init(){
    memset(head,-1,sizeof(head));
    memset(nxt,-1,sizeof(nxt));
    memset(du,0,sizeof(du));
    E=0;
}
void addedge(int u,int v){
    Edge[E]=edge(u,v);
    pre[E]=head[u];
    head[u]=E;
    E++;
    Edge[E]=edge(v,u);
    pre[E]=head[v];
    head[v]=E;
    E++;
}
void dfs(int u){
    while(head[u]!=-1){
        du[u]--;
        int id=head[u],v=Edge[id].v;
        if(id&1) ans[(id>>1)+1]=0;
        else ans[(id>>1)+1]=1;
        int Pre,Nxt;
        head[u]=pre[id];
        Pre=pre[id];
        Nxt=nxt[id];
        if(Pre!=-1) nxt[Pre]=Nxt;
        if(Nxt!=-1) pre[Nxt]=Pre;
        id^=1;
        if(head[v]==id)
            head[v]=pre[id];
        Pre=pre[id];
        Nxt=nxt[id];
        if(Pre!=-1) nxt[Pre]=Nxt;
        if(Nxt!=-1) pre[Nxt]=Pre;

        u=v;
        if(du[v]) du[v]--;
    }
}
int main(){
    scanf("%d",&t);
    while(t--){
        init();
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++){
            scanf("%d%d",&a,&b);
            addedge(a,b);
            du[a]++,du[b]++;
        }
        for(int i=0;i<E;i++) if(pre[i]!=-1)
            nxt[pre[i]]=i;
        for(int i=1;i<=n;i++)
            nxt[head[i]]=-1;
        for(int i=1;i<=n;i++) if(du[i]&1)
            dfs(i);
        for(int i=1;i<=n;i++) if(du[i])
            dfs(i);
        for(int i=1;i<=m;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}
View Code

 

posted @ 2015-08-08 11:48  轶辰  阅读(158)  评论(0编辑  收藏  举报