題意:有兩場表演,n個藝術家,根據規則找出我們要挑選的人的編號,輸出編號。
規則1 保證每個人只能參加一場表演,也就是同一個藝術家不能出現在兩場表演中
規則2 兩場表演參演的藝術家的數量是相同的
規則3 第一場可以演小丑的藝術家的數量要和第二場表演雜技的藝術家數量保持相同
分析:
很久沒擼代碼看到這題有點蒙,按說應該挺簡單的。。。結果還是很久沒想明白。。。
首先我們發現輸入是兩行數據,一行表示第i個人能不能演小丑,一行表示第i個人能不能演雜技,那麼也就是說,把整個藝術家羣體看做一個集合,可知爲了計算方便不出錯,可以分爲四個小集合,分別是兩種都不能演的藝術家數量A,只能演雜技的藝術家數量B,只能演小丑的藝術家數量C,以及兩種都能演的藝術家數量D。
前兩個規則都好搞定,就是第三個規則不好保證,而把藝術家分集合設未知數就可以巧妙地構造恆等關係,從而列出一下兩個方程。
我們設a,b,c,d爲第一場表演在四個集合中所選藝術家的數量。
那麼可知
(規則二)
(規則三:第一組小丑可演小丑數量 = 第二組雜技數量)
發現:兩個方程四個未知數
枚舉任意兩個那麼就可以根據這兩個等式把剩下兩個未知數求出來,根據求出的未知數就可以把對應集合的藝術家下標輸出出來,由於任意滿足條件的答案皆可。
這道題就是一個數學題,沒有啥編程難點可言,只要邏輯清晰,還是能很快AC的- -…
所以關於問題中有明顯數量關係約束的題目,不妨設未知數解方程組解決。
複雜度:O()
代碼:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5010;
vector<int>c,s,com,none;
int bokc[maxn],boks[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%1d",&bokc[i]);
}
for(int i=1;i<=n;i++){
scanf("%1d",&boks[i]);
}
for(int i=1;i<=n;i++){
if(boks[i]==bokc[i]){
if(boks[i])com.push_back(i);
else none.push_back(i);
}
if(boks[i]!=bokc[i]){
if(bokc[i])c.push_back(i);
if(boks[i])s.push_back(i);
}
}
int a,b,C,d;
bool yes = 0;
for(int i=0;i<=min((int)none.size(),n/2);i++){//
//枚舉a
a = i;//a = 0
d = s.size()+com.size()-n/2 + a; //d = 0
if(d<0)continue;
int bc = n/2-a-d;// bc = 2
if(bc<0)continue;
for(int j = 0;j<=min((int)c.size(),n/2);j++){
//枚舉C
C = j;
b = bc-C;
if(a+b+C+d!=n/2)continue;
if(C+d!=s.size()-b+com.size()-d)continue;
bool f=0;
//所有continue都是非法的情況 這裏注意就算是前面合法,數量超過實際情況也是非法
if(a>none.size())continue;
if(b>s.size())continue;
if(C>c.size())continue;
if(d>com.size())continue;
for(int o = 0;o<a;o++){
if(!f)printf("%d",none[o]),f=1;
else printf(" %d",none[o]);
}
for(int o = 0;o<b;o++){
if(!f)printf("%d",s[o]),f=1;
else printf(" %d",s[o]);
}
for(int o = 0;o<C;o++){
if(!f)printf("%d",c[o]),f=1;
else printf(" %d",c[o]);
}
for(int o = 0;o<d;o++){
if(!f)printf("%d",com[o]),f=1;
else printf(" %d",com[o]);
}
yes = 1;
break;
}
if(yes)break;
}
if(!yes)puts("-1");
return 0;
}