题目大意:
给出一个树的点数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;
}