2022 RoboCom 世界机器人开发者大赛-本科组(省赛)T4, T5

RC-u4 攻略分队

题意
把 6 支队伍分成两组,把所有的可能方案按照下面的筛选方式找到最佳方案:
在这里插入图片描述

思路
比较简洁的一个方法是,将每一条方案中的元素都存储到结构体中,然后在结构体中重载运算符,根据给出的筛选策略将所有方案排序,排过序之后的首条方案便是最佳方案。
怎么按照筛选策略排序呢?
对于一条筛选,在结构体中申请元素表示该筛选条件满不满足,如果满足置为1,否则为0。在重载小于号时,按照该元素从大到小排序。这样满足该条件的就放到了前面,不满足的就在后面。

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)

const int N = 200010, mod = 1e9+7;
int T, n, m;

//队伍结构体
struct node{
	int cnt;
	int tan, gong, zhi;
}dui[N];

//方案结构体
struct ST{
	int ou[7]; //第一组的所有队伍 
	int ya[7]; //第二组的所有队伍 
	int cnt1, cnt2; //两组的队伍个数 
	int zg; //指挥官和工兵都有 
	int zhi; //有指挥官 
	int cha; //两组人数之差 
	int tan; //有坦克 
	int more; //是否第一组比第二组人多 
	
	friend bool operator < (ST a, ST b)
	{
		if(a.tan != b.tan) return a.tan > b.tan; //筛选条件0 
		if(a.zg != b.zg) return a.zg > b.zg; //条件1
		if(a.zhi != b.zhi) return a.zhi > b.zhi; //2
		if(a.cha != b.cha) return a.cha < b.cha; //3
		if(a.more != b.more) return a.more > b.more; //4 
		for(int i=1;i<=min(a.cnt1, b.cnt1);i++) //5
			if(a.ou[i] != b.ou[i]) return a.ou[i] < b.ou[i];
	}
}a[N];

signed main(){
	Ios;
	for(int i=1;i<=6;i++) cin >> dui[i].cnt;
	
	for(int i=1;i<=6;i++)
	{
		string s; cin >> s;
		if(s[0] == '1') dui[i].tan = 1;
		if(s[1] == '1') dui[i].gong = 1;
		if(s[2] == '1') dui[i].zhi = 1;
	}
	
	for(int i=0;i<64;i++) //二进制枚举所有分配方案
	{
		int cnt1=0, cnt2=0;
		int sum1 = 0, sum2 = 0;
		for(int j=1;j<=6;j++) //每一位的01对应分配
		{
			if((i >> j-1) & 1){
				if(dui[j].cnt) a[i].ou[++cnt1] = j, sum1 += dui[j].cnt;
			}
			else{
				if(dui[j].cnt) a[i].ya[++cnt2] = j, sum2 += dui[j].cnt;
			}
		}
		a[i].cnt1 = cnt1;
		a[i].cnt2 = cnt2;
		
		int tan1 = 0, tan2 = 0, zhi1 = 0, zhi2 = 0, gong1 = 0, gong2 = 0;
		for(int j=1;j<=cnt1;j++)
		{
			int x = a[i].ou[j];
			if(dui[x].tan) tan1 = 1;
			if(dui[x].zhi) zhi1 = 1;
			if(dui[x].gong) gong1 = 1;
		}
		for(int j=1;j<=cnt2;j++)
		{
			int x = a[i].ya[j];
			if(dui[x].tan) tan2 = 1;
			if(dui[x].zhi) zhi2 = 1;
			if(dui[x].gong) gong2 = 1;
		}
		
		if(tan1 && tan2) a[i].tan = 1;
		if(zhi1 && zhi2 && gong1 && gong2) a[i].zg = 1;
		if(zhi1 && zhi2) a[i].zhi = 1;
		a[i].cha = abs(sum1 - sum2);
		if(sum1 > sum2) a[i].more = 1;
	}
	
	sort(a, a+64); //将所有方案按照给定的筛选条件排序
	
	ST ans = a[0]; //首个元素便是最优方案 
	if(!ans.tan){
		cout << "GG";
		return 0;
	}
	for(int i=1;i<=ans.cnt1;i++){
		cout << ans.ou[i];
		if(i!=ans.cnt1) cout << " ";
	}
	cout << endl;
	for(int i=1;i<=ans.cnt2;i++){
		cout << ans.ya[i];
		if(i!=ans.cnt2) cout << " ";
	}
	
	return 0;
}

然后还有一个方法就是,一点一点循环判断,如果方案唯一就退出,否则就执行下一条筛选…
写的比较多,比较烦。
而且还不知道为什么有一个点过不去。

#include<bits/stdc++.h>
using namespace std;

const int N = 100010;
int n, m;
struct node{
	int cnt;
	int mt, bing, zhihui;
}a[N];
int x[N], y[N];
int cntx, cnty;
int cnt;
vector<int> ans[N][2];
int f[N];

void pd()
{
	int flag = 0;
	for(int i=1;i<=cntx;i++)
	{
		int idx = x[i];
		if(a[idx].mt) flag = 1;
	}
	if(!flag) return;
	
	flag = 0;
	for(int i=1;i<=cnty;i++)
	{
		int idx = y[i];
		if(a[idx].mt) flag = 1;
	}
	if(!flag) return;
	
	cnt++;
	for(int i=1;i<=cntx;i++) ans[cnt][0].push_back(x[i]);
	for(int i=1;i<=cnty;i++) ans[cnt][1].push_back(y[i]);
}

void dfs(int u)
{
	if(u==7)
	{
		pd();
		return;
	}
	
	x[++cntx] = u;
	dfs(u+1);
	cntx--;
	
	y[++cnty] = u;
	dfs(u+1);
	cnty--;
}

bool Less(vector<int> v1, vector<int> v2)
{
	int m = min(v1.size(), v2.size());
	
	for(int i=0;i<m;i++)
	{
		if(v1[i] < v2[i]) return 1;
		else if(v1[i] > v2[i]) return 0;
	}
}

int main()
{
	for(int i=1;i<=6;i++) cin >> a[i].cnt;
	
	for(int i=1;i<=6;i++)
	{
		string s; cin >> s;
		if(s[0]=='1') a[i].mt = 1;
		if(s[1]=='1') a[i].bing = 1;
		if(s[2]=='1') a[i].zhihui = 1;
	}
	
	dfs(1);
	
	//1 
	int sum = 0, ansi = 0;
	for(int i=1;i<=cnt;i++)
	{
		vector<int> v1 = ans[i][0];
		vector<int> v2 = ans[i][1];
		
		int flag1 = 0, flag2 = 0;
		for(int x : v1)
		{
			if(a[x].zhihui) flag1 = 1;
			if(a[x].bing) flag2 = 1;
		}
		if(!flag1 || !flag2){
			f[i] = 1;
			continue;
		}
		
		flag1 = 0, flag2 = 0;
		for(int x : v2)
		{
			if(a[x].zhihui) flag1 = 1;
			if(a[x].bing) flag2 = 1;
		}
		if(!flag1 || !flag2){
			f[i] = 1;
			continue;
		}
		
		sum ++;
		ansi = i;
	}
	if(sum == 1)
	{
		vector<int> v1 = ans[ansi][0];
		vector<int> v2 = ans[ansi][1], res1, res2;
		
		for(int i=0;i<v1.size();i++){
			int x = v1[i];
			if(a[x].cnt) res1.push_back(x);
		}
		for(int i=0;i<v2.size();i++){
			int x = v2[i];
			if(a[x].cnt) res2.push_back(x);
		}
		
		for(int i=0;i<res1.size();i++){
			cout << res1[i];
			if(i!=res1.size()-1) cout << " ";
		}
		cout << endl;
		for(int i=0;i<res2.size();i++){
			cout << res2[i];
			if(i!=res2.size()-1) cout << " ";
		}
		
		return 0;
	}
	
	if(sum == 0)
	{
		for(int i=1;i<=cnt;i++) f[i] = 0;
		
		//2
		sum = 0;
		for(int i=1;i<=cnt;i++)
		{
			vector<int> v1 = ans[i][0];
			vector<int> v2 = ans[i][1];
			
			int flag1 = 0, flag2 = 0;
			for(int x : v1)
			{
				if(a[x].zhihui) flag1 = 1;
			}
			if(!flag1){
				f[i] = 1;
				continue;
			}
			
			flag1 = 0, flag2 = 0;
			for(int x : v2)
			{
				if(a[x].zhihui) flag1 = 1;
			}
			if(!flag1){
				f[i] = 1;
				continue;
			}
			
			sum ++;
			ansi = i;
		}
		if(sum == 1)
		{
			vector<int> v1 = ans[ansi][0];
			vector<int> v2 = ans[ansi][1], res1, res2;
			
			for(int i=0;i<v1.size();i++){
				int x = v1[i];
				if(a[x].cnt) res1.push_back(x);
			}
			for(int i=0;i<v2.size();i++){
				int x = v2[i];
				if(a[x].cnt) res2.push_back(x);
			}
			
			for(int i=0;i<res1.size();i++){
				cout << res1[i];
				if(i!=res1.size()-1) cout << " ";
			}
			cout << endl;
			for(int i=0;i<res2.size();i++){
				cout << res2[i];
				if(i!=res2.size()-1) cout << " ";
			}
			
			return 0;
		}
		
		if(sum == 0){
			for(int i=1;i<=cnt;i++)
				f[i] = 0;
		}
	}
	
	//3
	sum = 0, ansi = 0;
	int maxa = 1e9;
	for(int i=1;i<=cnt;i++)
	{
		if(f[i]) continue;
		vector<int> v1 = ans[i][0];
		vector<int> v2 = ans[i][1];
		
		int sum1 = 0, sum2 = 0;
		for(int x : v1)
		{
			sum1 += a[x].cnt;
		}
		
		for(int x : v2)
		{
			sum2 += a[x].cnt;
		}
		
		if(abs(sum1 - sum2) < maxa){
			maxa = abs(sum1 - sum2);
			ansi = i;
			sum = 1;
		}
		else if(abs(sum1 - sum2) == maxa){
			sum ++;
		}
	}
	
	if(sum == 1)
	{
		vector<int> v1 = ans[ansi][0];
		vector<int> v2 = ans[ansi][1], res1, res2;
		
		for(int i=0;i<v1.size();i++){
			int x = v1[i];
			if(a[x].cnt) res1.push_back(x);
		}
		for(int i=0;i<v2.size();i++){
			int x = v2[i];
			if(a[x].cnt) res2.push_back(x);
		}
		
		for(int i=0;i<res1.size();i++){
			cout << res1[i];
			if(i!=res1.size()-1) cout << " ";
		}
		cout << endl;
		for(int i=0;i<res2.size();i++){
			cout << res2[i];
			if(i!=res2.size()-1) cout << " ";
		}
		
		return 0;
	}
	
	sum = 0, ansi = 0;
	for(int i=1;i<=cnt;i++)
	{
		if(f[i]) continue;
		vector<int> v1 = ans[i][0];
		vector<int> v2 = ans[i][1];
		
		int sum1 = 0, sum2 = 0;
		for(int x : v1)
		{
			sum1 += a[x].cnt;
		}
		
		for(int x : v2)
		{
			sum2 += a[x].cnt;
		}
		
		if(abs(sum1 - sum2) != maxa) f[i] = 1;
	}
	
	//4
	sum = 0, ansi = 0, maxa = 1e9;
	for(int i=1;i<=cnt;i++)
	{
		if(f[i]) continue;
		vector<int> v1 = ans[i][0];
		vector<int> v2 = ans[i][1];
		
		int sum1 = 0, sum2 = 0;
		for(int x : v1)
		{
			sum1 += a[x].cnt;
		}
		
		for(int x : v2)
		{
			sum2 += a[x].cnt;
		}
		
		if(sum1 <= sum2) f[i] = 1;
		else{
			sum++;
			ansi = i;
		}
	}
	if(sum == 1)
	{
		vector<int> v1 = ans[ansi][0];
		vector<int> v2 = ans[ansi][1], res1, res2;
		
		for(int i=0;i<v1.size();i++){
			int x = v1[i];
			if(a[x].cnt) res1.push_back(x);
		}
		for(int i=0;i<v2.size();i++){
			int x = v2[i];
			if(a[x].cnt) res2.push_back(x);
		}
		
		for(int i=0;i<res1.size();i++){
			cout << res1[i];
			if(i!=res1.size()-1) cout << " ";
		}
		cout << endl;
		for(int i=0;i<res2.size();i++){
			cout << res2[i];
			if(i!=res2.size()-1) cout << " ";
		}
		
		return 0;
	}
	
	vector<int> t;
	for(int i=1;i<=10;i++) t.push_back(1e9);
	
	sum = 0, ansi = 0, maxa = 1e9;
	for(int i=1;i<=cnt;i++)
	{
		if(f[i]) continue;
		vector<int> v1 = ans[i][0];
		if(Less(v1, t)){
			t = v1;
			sum = 1;
			ansi = i;
		}
	}
	
	if(sum == 1)
	{
		vector<int> v1 = ans[ansi][0];
		vector<int> v2 = ans[ansi][1], res1, res2;
		
		for(int i=0;i<v1.size();i++){
			int x = v1[i];
			if(a[x].cnt) res1.push_back(x);
		}
		for(int i=0;i<v2.size();i++){
			int x = v2[i];
			if(a[x].cnt) res2.push_back(x);
		}
		
		for(int i=0;i<res1.size();i++){
			cout << res1[i];
			if(i!=res1.size()-1) cout << " ";
		}
		cout << endl;
		for(int i=0;i<res2.size();i++){
			cout << res2[i];
			if(i!=res2.size()-1) cout << " ";
		}
		
		return 0;
	}
	
	cout << "GG";
	
	return 0;
}

经验
场上dfs搜出所有方案之后,一步一步循环判断,如果找到唯一解就退出,否则进入下一条继续判断…写了半个多钟头没写完,发现样例都没跑出来,然后就没有勇气往下接写了,直接去看下一题了。。
加上存储所有方案用vector存的,后面判断也写的有点烦。
应该想清楚后面应该怎么接着处理,再选择合适的方式来存放数据。免得后面就很麻烦。


RC-u5 树与二分图

题意
给定一个 n n n 节点的树,问有多少个点对 ( i , j ) (i, j) (i,j) 满足:

  • 树中节点 i i i j j j 之间没有边直接相连;
  • 将无向边 ( i , j ) (i, j) (i,j) 加上之后整个树能构成二分图。

2 ≤ N ≤ 1 0 6 2≤N≤10^6 2N106

思路
要知道,一棵树本来就是一个二分图:根节点确定之后,深度为奇数的点在一个集合,深度为偶数的点在另一集合。

那么现在要连接两个节点,连接之后还要满足二分图,那肯定是深度为奇数的点向深度为偶数的点连边,或者深度为偶数的点向深度为奇数的点连边。

那么就可以从上到下遍历每一个节点,其和之前遍历过的深度奇偶性不同的所有点连边。因为要满足连边前两节点不直接相连,所以其父节点要去掉,点数-1。

或者记录每一层有多少节点,对于每一层来说,这一层的节点数 *(之前奇偶性不同层数的节点数-1)便是这一层的节点和上面节点连边的方案数。每一层这样的方案数相加便是总的方案数。

Code

#include<bits/stdc++.h>
using namespace std;

const int N = 1000010;
int n, m;
int a[N];
vector<int> e[N];
int f[N], flor[N];

void bfs()
{
	queue<int> que;
	que.push(1);
	f[1] = 1;
	a[1] = 1;
	
	while(que.size())
	{
		int x = que.front(); que.pop();
		for(int tx : e[x])
		{
			if(f[tx]) continue;
			f[tx] = 1;
			
			flor[tx] = flor[x] + 1;
			a[flor[tx]] ++;
			que.push(tx);
		}
	}
}

int main(){
	cin >> n;
	for(int i=1;i<n;i++)
	{
		int x, y;cin >> x >> y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	
	flor[1] = 1;
	bfs();
	
	long long cnt0 = 0, cnt1 = 0;
	long long ans = 0;
	for(int i=1;i<=n;i++)
	{
		if(i%2) cnt1 += a[i];
		else cnt0 += a[i];
		
		if(i%2)
		{
			if(a[i] && cnt0) ans += a[i]*(cnt0-1);
		}
		else if(a[i] && cnt1) ans += a[i]*(cnt1-1);
	}
	cout << ans;
	
	return 0;
}

T4 写了半个多钟头没有结果,样例都跑不出来就没有勇气继续写了,先去看了最后一题。看到二分图,又觉得是最后一题,应该很难吧,所以就直接暴力跑了个染色法判定拿了个暴力分。。都没有继续往下想。。
回过头来看 T4 也不想写了。。

继续训练吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值