https://ac.nowcoder.com/acm/contest/67741/E
题目叫做本题主要考察贪心,实际上不是
题目大意:
t组测试,每组给出一个n和m,n是初始选手数量,然后给出这n个选手的初始分数,接着给出m对数,为每次对战的两个选手。规则是赢+3,输+0,平都+1。
赛时状态:
比赛时,发现这题名字叫贪心,而且最气人的是,看帮时AC第三的题就是这道,于是乎,照着贪心写了。完全没考虑数据量如此小,也有迷惑性在内,因为t有一个范围,n,m又有范围,也没怎么具体看,误认为范围巨大。
题目思路
用dfs枚举所有组的三种情况,然后得出最小的rk.
看完方法后的第一次补题目
之前学过dfs,于是完全按照之前全排列等的回溯逻辑去写,其实第一次补提时,完全没深入理解dfs,仅仅是背了个模板。于是写出了内存超限,运行超时,等各种错误。附上代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
vector<int>arr;
int cot=0; int te=1,rk=1;
int dfs(map<pair<int,int>,int> M,vector<int> arr,int n){
if(n>=cot){
for(int i=1;i<=arr.size();i++){
if(arr[i]>arr[1]) te++;
}
rk=max(te,rk);
}
for(auto &x:M){
if(x.second){
x.second--;
arr[x.first.first]+=3;
dfs(M,arr,n+1);
arr[x.first.second]+=3;
dfs(M,arr,n+1);
arr[x.first.first]++,arr[x.first.second]++;
dfs(M,arr,n+1);
x.second++;
}
}
return rk;
}
signed main(){
int t;cin>>t;
while(t--){
int n,m;cin>>n>>m;
arr.claer();
arr.resize(n);
cot=0;
for(int i=1;i<=n;i++) cin>>arr[i];
map<pair<int,int>,int>M;
for(int i=0;i<m;i++){
int x,y; cin>>x>>y;
if(x>y) swap(x,y);
if(x==1) arr[1]+=3;
else{
M[{x,y}]++;
cot++;
}
}
//cout<<dfs(M,arr,0)<<"\n";
}
}
代码问题一:对数组和pair结合体理解不到位
完全没必要利用map存值进去,以前没写过一个引索能进行两个值的索引的数组,所以对vector<pair<int,int>>的使用不到位,这题这样用,确实能避免许多麻烦
代码问题二:对dfs的理解不到位
dfs(int x){
if(x>n) return 数组 //从1开始版本
for(int i=1;i<=n;i++){
if(!bool[i]){
arr[x]=i;//此层
bool[i]=ture; //此数
dfs(x+1);
bool[x]=false;
}
}
}
误认为dfs的回溯功能只能是for循环结合bool特判实现的,但其实不然,for循环主要用于循环填数,全排列的实现类似滚动数组,最外层的顺序是先利全false的bool将一整个数组填入如:1.2.3。 最后一层bool[1.2.3]都=ture。由于递归的回溯,会回到f(2),3那层被全部释放(包括bool[3]是ture这回事),这时的for指向了3,所以f(2)=3,又让bool[2]=false,这样就能将f(3)=2了,由于f(2)那里本身是不存在bool[2]=ture,所以下一步f(3)也能顺利赋到2。同理,最后一层的所有东西都被释放。刚刚我们退到了dfs(2),这次回退到dfs(1),可bool[1]=ture,于是for指向了2,于是arr[1]=2,bool[1]=ture。
理解完递归后,于是发现,这题只需要暴力遍历三种情况就行
因为我想要的效果是,从1组对战,到第m组,每个对战都进行三种情况的枚举。我需要的效果是,每组都3种情况,那一共是3^m种情况。请看dfs代码:
void dfs(int x){
tr=1;
if(x==m){
for(int i=1;i<=n;i++){
if(arr[i]>arr[1]) tr++;
}
rk=min(tr,rk);
return ;
}
for(int i=1;i<=3;i++){
if(i==1){
arr[ma[x].first]+=3;
dfs(x+1);
arr[ma[x].first]-=3;
}
if(i==2){
arr[ma[x].second]+=3;
dfs(x+1);
arr[ma[x].second]-=3;
}
else{
arr[ma[x].first]++,arr[ma[x].second]++;
dfs(x+1);
arr[ma[x].first]--,arr[ma[x].second]--;
}
}
}
完整代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int arr[102];
vector<pair<int,int>>ma;
int n,m;
int rk=10000,tr=1;
void dfs(int x){
tr=1;
if(x==m){
for(int i=1;i<=n;i++){
if(arr[i]>arr[1]) tr++;
}
rk=min(tr,rk);
return ;
}
for(int i=1;i<=3;i++){
if(i==1){
arr[ma[x].first]+=3;
dfs(x+1);
arr[ma[x].first]-=3;
}
if(i==2){
arr[ma[x].second]+=3;
dfs(x+1);
arr[ma[x].second]-=3;
}
else{
arr[ma[x].first]++,arr[ma[x].second]++;
dfs(x+1);
arr[ma[x].first]--,arr[ma[x].second]--;
}
}
}
signed main(){
int t;cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>arr[i];
for(int i=0;i<m;i++){
int x,y;cin>>x>>y;
ma.push_back({x,y});
}
dfs(0);
ma.clear();
memset(arr,0,sizeof(arr));
cout<<rk<<'\n';
rk=10000,tr=1;
}
}
样例给的非常好,因为写好后tr(第二行)未进行初始化,导致样例没过,调了很久之后才醒悟,return并不能将rt(全局)清除。 收获满满。