ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[20220404联考] 条条下水道通祖安

2022-04-04 17:00:36  阅读:143  来源: 互联网

标签:度数 通祖安 le return int TT MAXN 20220404 联考


前言

这个构造又不是构造可行解,是最小化答案,不推式子不打表找规律直接想当然写个做法有分就有鬼了。

有鬼!想当然做法可以过样例,数据有样例!

题目

没有链接

俗话说得好,条条下水道通祖安。这天祖安有打算建一些下水道通道来使得 \(n\) 个地点达到要求:

  • 为方便管理,每个点度数至少要有 \(k\)。

  • 为防止藩镇割据,度数为 \(k\) 的点两两间不能有通道。

  • 两点间至多建一条通道。

  • 为了节省经费,建造的通道要最少。

你能帮帮祖安的城市设计师吗?

样例输入

5 2

样例输出

6
1 2
1 3
1 4
2 5
3 5
4 5

\(2\le k\le 10;2k+1\le n\le 1000.\)

讲解

想当然做法是 \(n-k\) 个点另外 \(k\) 个点都连边,除了样例啥也过不了。

我们这样想,我们要使连边最少肯定有点度数为 \(k\),我们试图枚举它的数量,但是为了和代码统一,我们记度数大于 \(k\) 的点有 \(x\) 个(左部),度数恰好为 \(k\) 的点就有 \(n-x\) 个(右部)。

令左部点内部有 \(y\) 条边, 那么有 \(k(n-x)+2y\ge (k+1)x\),我们需要最小化 \(k(n-x)+y\),可以发现枚举 \(x\) 后只需最小化 \(y\)。

随便化一化式子发现 \(y=\max\{0,\lceil\frac{(2k+1)x-kn}{2}\rceil\}\),这样得到了最小的 \(k(n-x)+y\) 对应的 \(x\) 之后,思考如何构造一组解。

首先把左右两部的 \(k(n-x)\) 条连边依次均匀连接,不难发现均匀连接是不劣的。

然后把左部点度数依然为 \(k\) 的边两两匹配连边,如果有单出来的随便再连一条即可。

代码

//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;

typedef long long LL;
const int MAXN = 1005;
int n,k;

LL Read()
{
	LL x = 0,f = 1; char c = getchar();
	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int tot,deg[MAXN];
pair<int,int> e[MAXN*MAXN];
bool vis[MAXN][MAXN];
void Add_Edge(int u,int v){
	e[++tot] = make_pair(u,v);
	++deg[u]; ++deg[v];
	vis[u][v] = vis[v][u] = 1;
}
int calc(int x){return k * (n-x) + Max(0,(int)ceil(0.5 * ((2*k+1)*x-k*n)));}

int main()
{
//	freopen("graph.in","r",stdin);
//	freopen("graph.out","w",stdout);
	n = Read(); k = Read(); int lef = 0,MIN = n*n+4;
	for(int i = 1;i <= n;++ i){
		int val = calc(i);
		if(val < MIN) MIN = val,lef = i;
	}
	for(int i = lef+1,lst = 1;i <= n;++ i)
		for(int j = 1;j <= k;++ j,lst = lst % lef + 1)
			Add_Edge(lst,i);
	int lst = 0;
	for(int i = 1;i <= lef;++ i)
		if(deg[i] == k){
			if(lst) Add_Edge(lst,i),lst = 0;
			else lst = i;
		}
	if(lst){
		for(int i = 1;i <= lef;++ i)
			if((lst ^ i) && !vis[i][lst])
				{Add_Edge(i,lst);break;}
	}
	Put(tot,'\n');
	for(int i = 1;i <= tot;++ i) Put(e[i].first,' '),Put(e[i].second,'\n');
	return 0;
}

总结?

最小化式构造先找最小值,再构造。

标签:度数,通祖安,le,return,int,TT,MAXN,20220404,联考
来源: https://www.cnblogs.com/PPLPPL/p/16099703.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有