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 2≤N≤106
思路
要知道,一棵树本来就是一个二分图:根节点确定之后,深度为奇数的点在一个集合,深度为偶数的点在另一集合。
那么现在要连接两个节点,连接之后还要满足二分图,那肯定是深度为奇数的点向深度为偶数的点连边,或者深度为偶数的点向深度为奇数的点连边。
那么就可以从上到下遍历每一个节点,其和之前遍历过的深度奇偶性不同的所有点连边。因为要满足连边前两节点不直接相连,所以其父节点要去掉,点数-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 也不想写了。。
继续训练吧!