URAL 1389 Roadworks 贪心

题目大意:

给出一个树的点数N,边数M(M = N - 1) 要求从其中挑出尽可能多的边,挑出来的边不能有共同顶点

输出挑出的边数和挑出的具体是那几条边

题面上说是要按照输入的格式输出那些边

不过亲测如果题目中有输入边1 2,但是你输出 2 1 的话也是会AC的,,

处理鸳鸯输出用一个小小的map的技巧就够了

整个选边的过程中要的思想就是贪心

对于每个点都用一个数组记录当前和这个点相连的未被访问过的点的数量,为1时可以考虑;每次都考虑这样的点,然后选择对应的边,然后处理其他收到影响的点的这个数组的值,这样每次都选只剩一条可选边相连的点,最终会得到最大的选边数量

代码如下:

这是考虑了输出格式的版本= =

不考虑输出格式时间可以减半,内存消耗可以减少一半以上

Result  :  Accepted     Memory  :  15805 KB     Time  :  796 ms

/*
 * Author: Gatevin
 * Created Time:  2014/7/24 10:14:42
 * File Name: test.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

#define maxn 100010

int n,m;
int du[maxn];
bool vis[maxn];
vector <int> G[maxn];
queue <int> q;
vector <pair<int, int> > answer;
map <int, int> M;

int main()
{
    scanf("%d %d",&n,&m);
    int tmp1, tmp2;
    memset(vis, 0, sizeof(vis));
    memset(du, 0, sizeof(du));
    for(int i = 1; i <= m; i++)
    {
        scanf("%d %d",&tmp1, &tmp2);
        M[tmp1*maxn + tmp2] = 1;
        M[tmp1 + tmp2*maxn] = 0;
        G[tmp1].push_back(tmp2);
        G[tmp2].push_back(tmp1);
        du[tmp1]++;
        du[tmp2]++;
    }
    for(int i = 1; i <= n; i++)
    {
        if(du[i] == 1)
            q.push(i);
    }
    while(!q.empty())
    {
        tmp1 = q.front();
        tmp2 = 0;
        q.pop();
        if(vis[tmp1]) continue;
        for(unsigned int i = 0; i <= G[tmp1].size() - 1; i++)
        {
            if(!vis[G[tmp1][i]])
            {
                answer.push_back(make_pair(tmp1, G[tmp1][i]));
                vis[tmp1] = 1;
                vis[G[tmp1][i]] = 1;
                tmp2 = G[tmp1][i];
                break;
            }
        }
        if(tmp2 != 0)
        {
            for(unsigned int i = 0; i <= G[tmp2].size() - 1; i++)
            {
                if(!vis[G[tmp2][i]])
                {
                    du[G[tmp2][i]]--;
                    if(du[G[tmp2][i]] == 1)
                        q.push(G[tmp2][i]);
                }
            }
        }
    }
    printf("%d\n",answer.size());
    for(unsigned int i = 0; i <= answer.size() - 1; i++)
    {
        if(M[answer[i].first * maxn + answer[i].second])
            printf("%d %d\n",answer[i].first, answer[i].second);
        else
            printf("%d %d\n",answer[i].second, answer[i].first);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值