G.真简单题(最短路)I.假简单题(三进制枚举)

在这里插入图片描述
思路:

这道题在比赛的时候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 1434890720(内部常数)=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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值