题面:
#include <iostream>
#include <queue>
#include <climits>
using namespace std;
int n, m, t, cnt, num;
int k;
const int MAXN = 2e5 + 5;
int head[MAXN];
int cnm[MAXN];//注:用于存储每一个数的位置
//由于可能会出现bug,那么就要
struct Node {
int to, next;
}e[MAXN];
void add(int x, int y)
{
e[cnt].next = head[x];
e[cnt].to = y;
head[x] = cnt++;
}
bool vis[MAXN];
bool cnmt[MAXN];//记录这一个数字有没有输出
struct nnode {
int v;//记录你的值
int ssum;//记录批次
friend bool operator<(nnode a, nnode b)
{
if (a.ssum == b.ssum)
{
return a.v > b.v;
}
return a.ssum > b.ssum;
}
};
struct node {
int xb;//有多少元素
int zuix;
priority_queue<nnode> a;//考虑批次,同一批次的选择最小的,知道xuanwanoperat
friend bool operator <(node a, node b)
{
if (a.xb == b.xb)
{
return a.zuix > b.zuix;
}
return a.xb < b.xb;//元素多的靠前
}
}from[MAXN];
priority_queue<node> q;//求出来
void init(int len)
{
for (int i = 0; i < len; i++)
{
head[i] = -1;
cnm[i] = INT_MAX;
cnmt[i] = 0;
vis[i] = 0;
from[i].xb = 0;
while (!from[i].a.empty())
{
from[i].a.pop();
}
}
cnt = 0;
num = 0;
}
void BFS(int i, bool z)
{
//求出连通块
int ni = 1;//你的批次
queue<int> xt;
vis[i] = 1;
xt.push(i);
from[num].zuix = INT_MAX;//初始化
while (!xt.empty())
{
int sz = xt.size();
while (sz--)
{
int now = xt.front();
xt.pop();
cnm[now] = min(ni, cnm[now]);
//std::cout << "在第" << num << "个连通块的第" << ni << "层找到了" << now << endl;
from[num].xb++;
from[num].a.push({ now , ni });
from[num].zuix = min(from[num].zuix, now);
for (int i = head[now]; ~i; i = e[i].next)
{
int v = e[i].to;
//std::cout << v << endl;
if (vis[v] == z)
{
vis[v] = 1 - z;
xt.push(v);
}
}
}
ni++;
}
}
int main()
{
//需要分类讨论
cin >> t;
while (t--)
{
while (!q.empty())
{
q.pop();
}
/*
5 4 1
1 2
2 3
3 1
4 5
*/
cin >> n >> m >> k;
init(n + 1);//已经初始化了
num = 1;
while (m--)
{
int xx, y;
cin >> xx >> y;
add(xx, y);
add(y, xx);
}
for (int i = 1; i <= n; i++)
{
if (vis[i] == 0)
{
BFS(i, 0);
num++;//更新标记
}
}
//num >= k表示图走不
num--;
//std::cout << "当前有" << num << "个连通块" << endl;
if (num >= k)
{
//刚好走完整一个图
//选择几个最大的,然后扔进去排序
for (int i = 1; i <= num; i++)
{
//把所有已经测试过的放进去
q.push(from[i]);//放进去了所有的
from[i].xb = 0;
}
//接下来,选择前面k个
//有num-1个连通块,就相当于我们希望可以让值越小越好
node zong;
zong.xb = 0;
while (k--)
{
node now = q.top();//已经找到了这些东西
while (!now.a.empty())
{
//把这些都放进去
//std::cout << "可到达" << now.a.top().v << endl;//你可以到达的点
zong.a.push(now.a.top());
zong.xb++;//增加数量
now.a.pop();
}
q.pop();
}
std::cout << zong.xb << endl;
while (!zong.a.empty())
{
std::cout << zong.a.top().v << " ";
zong.a.pop();
}
cout << endl;
}
else
{
//还有多余次数
for (int i = 1; i <= n; i++)
{
//std::cout << i << " " << cnm[i] << endl;
if (cnm[i] > i)
{
//你不是可以的
//std::cout << i << "可以进一步优化" << endl;
BFS(i, vis[i]);
num++;//更新标记
}
}
//把剩下的放进去
for (int i = 1; i <= num; i++)
{
//把所有已经测试过的放进去
q.push(from[i]);
}
//判断能不能取
//接下来,选择前面k个
//有num-1个连通块,就相当于我们希望可以让值越小越好
node zong;
zong.xb = 0;
while (k--)
{
//cout << "k = " << k << endl;
node now = q.top();//已经找到了这些东西
while (!now.a.empty())
{
//把这些都放进去
//cout << "还有" << now.a.size() << "个元素" << endl;
if (cnmt[now.a.top().v] == 1)
{
now.a.pop();
//已经来过了
continue;
}
cnmt[now.a.top().v] = 1;
//std::cout << "可到达" << now.a.top().v << endl;//你可以到达的点
zong.a.push(now.a.top());
zong.xb++;//增加数量
now.a.pop();
}
q.pop();
if (q.empty())
{
//为空
break;
}
}
std::cout << zong.xb << endl;
while (!zong.a.empty())
{
std::cout << zong.a.top().v << " ";
zong.a.pop();
}
cout << endl;
}
}
return 0;
}
全部评论
(0) 回帖