2022 Robocom 省赛题解

T4 给定6个队伍,让分成两个不为空的小组。题很简单,但是有6个规则,逻辑判断很麻烦。这里学了一手,可以把所有解放入结构体,进行优先级排序,排序后的第一个就是最优解。
O(2^6 * log(2 ^ 6))
Code:

#include
using namespace std;
int cnt[10];
int a[10][5];
int n,m,k,T;
int ans = 1;
struct node{
	int x;
	bool f1,f2,f3; //规则0、1、2 
	int dis; //人数差
	bool f4; //左边人多
	vector<int> l;
	bool operator<(const node&rhs)const
	{
		if(f1 != rhs.f1) return f1 > rhs.f1;
		if(f2 != rhs.f2) return f2 > rhs.f2;
		if(f3 != rhs.f3) return f3 > rhs.f3;
		if(dis != rhs.dis) return dis < rhs.dis;
		if(f4 != rhs.f4) return f4 > rhs.f4;
		for(int i=0;i<min(l.size(),rhs.l.size());++i)
		{
			int t1 = l[i],t2 = rhs.l[i];
			if(t1 != t2) return t1 < t2;
		}
	}
}v[100];
void solve()
{
	n = 6;
	for(int i=0;i<n;++i) cin>>cnt[i];
	int t = 0;
	for(int i=0;i<n;++i)
	{
		for(int j=0;j<3;++j)
		scanf("%1d",&a[i][j]);
		if(a[i][0]) t++;
	}
	if(t < 2)
	{
		cout<<"GG";
		return ;
	}
	for(int i=0;i<(1<<6);++i)
	{
		v[i].x = i;
		v[i].f1 = v[i].f2 = v[i].f3 = v[i].f4 = 0;
		int x = i;
		vector<int> l,r;
		for(int i=0;i<n;++i)
		{
			if(!cnt[i]) continue;
			if(x>>i&1) l.push_back(i);
			else r.push_back(i);
		}
		if(!l.size() || !r.size()) continue;
		v[i].l = l;
		bool f1 = 0,f2 = 0,f3 = 0,f4 = 0,f5 = 0,f6 = 0;
		int sum1 = 0,sum2 = 0;
		for(int i=0;i<l.size();++i)
		{
			int x = l[i];
			if(a[x][0]) f1 = 1;
			if(a[x][1]) f2 = 1;
			if(a[x][2]) f3 = 1;
			sum1 += cnt[x];
		}
		for(int i=0;i<r.size();++i)
		{
			int x = r[i];
			if(a[x][0]) f4 = 1;
			if(a[x][1]) f5 = 1;
			if(a[x][2]) f6 = 1;
			sum2 += cnt[x];
		}
		if(f1 && f4) v[i].f1 = 1;
		if(f2 && f3 && f5 && f6) v[i].f2 = 1;
		if(f3 && f6) v[i].f3 = 1;
		v[i].dis = abs(sum1-sum2);
		if(sum1 > sum2) v[i].f4 = 1;
		else v[i].f4 = 0;
	}
	sort(v,v+64);
	int x = v[0].x;
	vector<int> l,r;
	for(int i=0;i<n;++i)
	{
		if(!cnt[i]) continue;
		if(x>>i&1) l.push_back(i+1);
		else r.push_back(i+1);
	}
	for(int i=0;i<l.size();++i)
	{
		if(i) cout<<" ";
		cout<<l[i];
	}
	cout<<"\n";
	for(int i=0;i<r.size();++i)
	{
		if(i) cout<<" ";
		cout<<r[i];
	}
}
signed main(void)
{
	solve();
	return 0;
}

T5
题意:
设 G=(V,E) 是一个无向图,如果顶点集合 V 可分割为两个互不相交的子集 (A,B),并且每条边 (i,j)∈E 的两个端点 i 和 j 分别属于这两个不同的顶点子集,则称图 G 为一个二分图。

现在给定一棵树 T,要求选择树中两个没有边相连的结点 i 和 j,使得将无向边 (i,j) 加进 T 后能够构成二分图。你的任务是计算满足这个要求的选择方案有多少种。

思路: 首先,给定的树一定是一个二分图,因为无环,每条边两边连的点黑白染色即可。那么,我们就可以先对给定的树进行黑白染色,假设黑色节点有x个,白色节点则是剩余的n-x个。所有黑色节点连向白色节点,最多有x*(n-x),原来有n-1条边,方案就是二者之差,这些边都可以分别加一次。

O(n)
Code:

#include
using namespace std;
const int N = 1e6+10;
vector<int> va[N];
int n,m,k,T;
bool vis[N];
void dfs(int cur,int fa,bool st)
{
	vis[cur] = st;
	for(int i=0;i<va[cur].size();++i)
	{
		int j = va[cur][i];
		if(j==fa) continue;
		dfs(j,cur,!st);
	}
}
void solve()
{
	cin>>n;
	for(int i=0;i<n-1;++i)
	{
		int x,y; cin>>x>>y;
		va[x].push_back(y),va[y].push_back(x);
	}
    dfs(1,0,1);
	int l = 0,r = 0;
	for(int i=1;i<=n;++i)
	{
	  if(vis[i]) l++;
	}
	r = n-l;
	long long ans = 1ll*l*r;
	ans -= (n-1);
	cout<<ans;
}
signed main(void)
{
	solve();
	return 0;
}

你可能感兴趣的:(pta,算法,c++,图论)