HDU 5438 Ponds (拓扑排序+DFS)2015 ACM/ICPC Asia Regional Changchun Online

来源:互联网 发布:周杰伦北大演讲知乎 编辑:程序博客网 时间:2024/05/17 09:09

【题目链接】:click here~~

【题目大意】:

题意:在一个无向图中有 p 个点, m 条边,每个点有一个值 vi 。不断的删去度数小于2的点直到不能删为止。求新图中所有点个数为奇数的连通分量的点值的和。
1<p<10^4,1<m<10^5

【思路】删边考虑类似拓扑排序的写法,不过topsort是循环一遍1到n结点入度为0的结点,然后加入到队列中,这里只要改一下度数小于等于1,最后DFS 判断一下

挫挫的代码:

/** Problem: HDU No.5438* Running time: 124MS* Complier: G++* Author: javaherongwei* Create Time:  10:31 2015/9/18 星期五*/#include <stdio.h>#include <queue>#include <string.h>#include <iostream>#include <algorithm>using namespace std;const int N=1e4+10;typedef long long LL;LL in[N];LL val[N];bool vis[N];bool vis2[N];vector <LL >G[N];int n,m;void topsort(){    queue <LL >que;    while(!que.empty()) que.pop();    for(int i=1; i<=n; ++i){        if(in[i]<=1)        {            if(in[i]==1) que.push(i); //!!!            vis[i]=true;        }    }    while(!que.empty()){        LL u=que.front(); que.pop();vis[u]=true;        for(int i=0; i<G[u].size(); ++i){ // !!!i<G[u].size()!!!            LL k=G[u][i];            if(--in[k]<=1){                if(in[k]==1) que.push(k); //!!!                vis[k]=true;            }        }    }}LL dfs(int u) // dfs 传入第一个结点进行搜索遍历判断{    queue<LL>que;    que.push(u);    vis2[u]=true;    LL sum=0;    LL len=0;    while(!que.empty()){        LL u=que.front();        que.pop();        sum+=val[u];        len++;        for(int i=0; i<G[u].size(); ++i){            LL k=G[u][i];            if(!vis[k]&&!vis2[k]){                que.push(k);                vis2[k]=true;            }        }    }    if(len&1) return sum;    else return 0;}int main(){    int t;    scanf("%d",&t);    while(t--){        memset(in,0,sizeof(in));        memset(val,0,sizeof(val));        memset(vis,false,sizeof(vis));        memset(vis2,0,sizeof(vis2));        for(int i=0; i<N; ++i) G[i].clear();        scanf("%d%d",&n,&m);        for(int i=1; i<=n; ++i) scanf("%lld",&val[i]);        for(int i=1; i<=m; ++i){            int u,v;            scanf("%d%d",&u,&v);            G[u].push_back(v);            G[v].push_back(u);            in[u]++;            in[v]++;        }        topsort();        LL sum=0;        for(int i=1; i<=n; ++i){            if(!vis[i]&&!vis2[i]) sum+=dfs(i);        }      printf("%lld\n",sum);    }    return 0;}

下午试了一下邻接表写法,比用vector存边耗时快一点了,109ms

代码:

/*  * Problem: HDU No.5438* Running time: 109MS  * Complier: G++  * Author: javaherongwei * Create Time:  14:51 2015/9/18 星期五*/  #include <stdio.h>#include <queue>#include <string.h>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int N=1e5+10;struct node{    int to,next;}edge[N<<1];int tot,head[N];int n,m;bool vis[N];int deg[N];int val[N];void init(){   tot=0;   memset(head,-1,sizeof(head));   memset(vis,false,sizeof(vis));   memset(deg,0,sizeof(deg));}void add_edge(int u,int v){    edge[tot].to=v;    edge[tot].next=head[u];    head[u]=tot++;}void topsort(){    queue<int >que;    while(!que.empty()) que.pop();    for(int i=1; i<=n; ++i)        if(deg[i]<=1) que.push(i);    while(!que.empty()){        int u=que.front();que.pop();vis[u]=true;        for(int i=head[u]; i!=-1; i=edge[i].next){            int k=edge[i].to;            if(!vis[k]){               if(--deg[k]<=1) que.push(k);            }        }    }}LL len,sum;void dfs(int u){    vis[u]=true;    len++;    sum+=val[u];    for(int i=head[u]; i!=-1; i=edge[i].next){        int k=edge[i].to;        if(!vis[k]){            dfs(k);        }    }}int main(){    int t;scanf("%d",&t);    while(t--){        init();        scanf("%d%d",&n,&m);        for(int i=1; i<=n; ++i) scanf("%d",&val[i]);        while(m--){            int u,v;            scanf("%d%d",&u,&v);            add_edge(u,v);            add_edge(v,u);            deg[u]++;deg[v]++;        }     topsort();     LL ans=0;     for(int i=1; i<=n; ++i){         if(!vis[i]){            len=0;            sum=0;            dfs(i);            if(len&1) ans+=sum;         }     }     printf("%lld\n",ans);    } return 0;}


0 0