思路:
这道题在比赛的时候WA了很多发,一直以为dfs漏掉了什么细节,我的做法是对于 i - a[i] 和 i + a[i],如果可以到达,就连一条边然后,对于一个点去类似bfs那样dfs,当有奇偶性不同的解的时候,就更新结果,结果RE了,贴上代码:
运行时错误的代码:
#include <bits/stdc++.h>
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define f(i,a,n) for(int i=a;i<n;++i)
#define ff(i,a,n) for(int i=a;i<=n;++i)
#define OP freopen("D:\\Users\\HP ZBook15\\CLionProjects\\untitled\\demo\\in.TXT","r",stdin);
#define CL freopen("D:\\Users\\HP ZBook15\\CLionProjects\\untitled\\demo\\out.TXT","w",stdout);
const int INF=0x3f3f3f3f;
using namespace std;
typedef long long ll;
typedef double dbl;
typedef pair<int, int> pi;
const int N=2e5+5;
int a[N];
vector<int> v[N];
int ans;
int dfs(int p,int k,int num){
for(int i=0;i<v[k].size();i++){
if((a[v[k][i]]+p)%2==1){
ans=min(ans,num+1);
}
else ans= min(dfs(p,v[k][i],num+1),ans);
}
return ans;
}
int main(){
// OP CL
int n;
cin>>n;
for(int i=1;i<=n;i++) {
cin>>a[i];
}
for(int i=1;i<=n;i++){
int t1=i+a[i],t2=i-a[i];
if(t1>=1&&t1<=n)v[i].push_back(t1);
if(t2>=1&&t2<=n)v[i].push_back(t2);
}
for(int i=1;i<=n;i++){
ans=1e9;
dfs(a[i],i,0);
if(i!=n){
if(ans==1e9)cout<<"-1"<<" ";
else cout<<ans<<" ";
}
else{
if(ans==1e9)cout<<"-1";
else cout<<ans;
}
}
}
/*
10
4 5 7 6 7 5 4 4 6 4
*/
正解:
建立两个点 0 和 n+1,让所有 a[i] 为偶数的点与 0 连一条价值为零的边,让所有 a[i] 为奇数的点与 n+1 连一条价值为零的边,对于 i - a[i] 和 i + a[i],如果可以到达,就连一条价值为 1 的边,对于偶数点,到达 n+1 的最短路径就是答案,对于奇数点,到达 0 的最短路就是答案,反向建图最短路即可
代码:
#include <bits/stdc++.h>
#define ll long long
const int maxn = 2e5+10;
using namespace std;
int a[maxn];
vector<pair<int, int> > ma[maxn];
queue<pair<int, int> > q;
int res[maxn];
int vis[maxn];
int w[maxn];
void BFS(int s){
q.push({s, 0});
memset(vis,0,sizeof vis);
memset(w,-1,sizeof w);
while(!q.empty()){
int now = q.front().first, val = q.front().second; q.pop();
if(vis[now]) continue;
vis[now] = 1, w[now] = val;
for(int i = 0; i < ma[now].size(); i++){
int u = ma[now][i].first, cost = ma[now][i].second;
q.push({u, val + cost});
}
}
}
int main(){
int n;
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) {
//建反边,价值1
if(i+a[i] <= n)ma[i+a[i]].push_back({i, 1});
if(i-a[i] >= 1)ma[i-a[i]].push_back({i, 1});
//价值0
if(a[i]&1)ma[n+1].push_back({i, 0});
else ma[0].push_back({i, 0});
}
//n+1与奇数点连,确定偶数点的最短距离
BFS(n+1);
for(int i = 1; i <= n; i++) if(a[i]%2==0) res[i] = w[i];
//类比
BFS(0);
for(int i = 1; i <= n; i++) if(a[i]%2==1) res[i] = w[i];
for(int i = 1; i <= n; i++) cout << res[i] << " ";
cout << endl;
return 0;
}
思路:
三进制枚举,暴搜,每个砝码只有三种状态:放左侧,放右侧,不取,直接三进制枚举即可,时间复杂度 O ( n 3 ) O(n^3) O(n3),n在15以内,也就是大概 14348907 ∗ 20 ( 内部常数 ) = 3 e 8 14348907*20(内部常数)=3e8 14348907∗20(内部常数)=3e8 次运算
代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5+10;
int a[maxn];
int n;
int main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
int FLAG = 1;
for(int i = 1; i <= n; i++) FLAG *= 3;
int res0 = 0, res1 = 0, res2 = 0;
for(int k = 1; k <= FLAG; k++){
int x = k;
int sum = 0;
for(int i = 1; i <= n; i++){
if(x % 3 == 1) sum += a[i];
if(x % 3 == 2) sum -= a[i];
x /= 3;
}
if(sum > 0) res0++;
if(sum == 0) res1++;
if(sum < 0) res2++;
}
cout << res0 << " " << res1 << " " << res2 << endl;
return 0;
}