AtCoder Beginner Contest 352 F题 Estimate Order

题目链接

思路:

        n很小考虑暴力搜索,但16的阶乘肯定是不行的,考虑缩小搜索范围。

由题目可知,对于有关联的位置,只要确定其中一个值,其他关联值便确定了。

我们将关联在一起的所有位置称为一个关联块,我们只需暴力搜索块的状态,

对于单点块,没有限制可以取任意值,所以我们在搜索的时候跳过单点块,

在最后搜索完之后在将单点块赋值成需要的值。

亿点点小细节:

        每个块有哪些点要怎么知道呢:在输入的时候建立双向边,边权为相反数。

要求块的时候,直接dfs即可。

        在这里有两个关于dfs的注意点:

        1.对于标记数组,若我们每次都初始化的话,时间会加一层n,可以优化。

我们可以发现对于每次搜索一个块,我们只需要知道这个点是现在这次搜到过的即可,

我们可以利用时间戳,将每次搜索记作为tol,表示这次搜索搜索过的点时间为tol。

这样就不用重置标记数组了;

        2.关于搜索块的回溯需要注意,需要先dfs到底再回溯,要按照出栈的顺序回溯;

        由于要回溯,所以我们将vis数组(就是1到n位置是谁)设置成vector类型,方便回溯。

又因为在搜索的时候可能会出现负值,所以将yes数组(就是存每个数是否出现,

并出现了几次)设置成map类型,要是用数组会下标越界。

        搜索的时候若该点单点成块或者该点已经赋值(vis的大小不为0),我们直接dfs(p+1)。

        搜索完毕后要如何判断是否合法:

        1.若有位置的值超过n或者小于1不合法

        2.若有的数取超过1不合法

        关于如何取答案:

        fff表示单点成块个数,l存的是为取到的数。若l的个数大于1,那么对于单点成块的

数就没有确定值,随便塞两个可行值表示这个点不唯一。若l的个数为1就将这个值赋值

给单点成块的点。最后如果一个点的set值不为1,那么就是不唯一。

        需要剪枝,不剪枝的话会有一个样例过不了。就是在搜索块的时候如果有位置的赋值

不合法,接下来就不进行dfs即可。

 代码:

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
const int inf=0x3f3f3f3f;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;

int n,m;
set<int> s[100];
unordered_map<int,int> yes;
vector<pii> v[100];
vector<int> vis[100];
int tf=0;
int col[100];
int tol=0;
int c(int x){
    int res=1;
    col[x]=tol;
    for(auto i:v[x]){
        int fi=i.first,se=i.second;
        if(col[fi]==tol) continue;
        int y=vis[x][vis[x].size()-1];
        if(y-se<1||y-se>n) tf=1;
        vis[fi].push_back(y-se);
        yes[y-se]++;
        col[fi]=tol;
        res+=c(fi);
    }
    return res;
}
void rc(int x){
    col[x]=tol;
    for(auto i:v[x]){
        int fi=i.first,se=i.second;
        if(col[fi]==tol) continue;
        rc(fi);
        int y=vis[x][vis[x].size()-1];
        vis[fi].pop_back();
        yes[y-se]--;
        if(yes[y-se]==0)
        	yes.erase(y-se);
        col[fi]=tol;
    }
}
void dfs(int p){
    if(p==n+1){
        int f=0,ff=0,fff=0;
        vector<int> l;
        for(int i=1;i<=n;i++){
        	if(vis[i].size()==0)
        		fff++;
        	if(yes.find(i)==yes.end()){
        		l.push_back(i);
			}
		}
        for(auto i:yes){
        	if(i.first<1||i.first>n){
        		f=1;break;
			}
			if(i.second>1){
				f=1;break;
			}
			ff++;
		}
        if(f||ff+fff!=n) return;
        for(int i=1;i<=n;i++){
            if(vis[i].size()==0){
                if(l.size()>1){
                    s[i].insert(l[0]);
                    s[i].insert(l[1]);
                }
                else if(l.size()){
                    s[i].insert(l[0]);
                }
            }
            else if(vis[i].size()){
                s[i].insert(vis[i][0]);
            }
        }
        return;
    }
    if(v[p].size()==0||vis[p].size()){
        dfs(p+1);
        return;
    }
    for(int i=1;i<=n;i++){
        if(yes[i]!=0) continue;
        vis[p].push_back(i);
        yes[i]++;
        tol++;
        col[p]=tol;
        tf=0;
        c(p);
        if(!tf)
        dfs(p+1);
        tol++;
        col[p]=tol;
        rc(p);
        yes[i]--;
        if(yes[i]==0)
        	yes.erase(i);
        vis[p].pop_back();
    }
}
void solve(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int a,b,c;cin>>a>>b>>c;
        v[a].push_back({b,c});
        v[b].push_back({a,-c});
    }
    dfs(1);
    for(int i=1;i<=n;i++){
        if(s[i].size()==1)
        cout<<*s[i].begin()<<' ';
        else
        cout<<-1<<' ';
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
   // cin>>t;
    while(t--){
        solve();
    }

}

        

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值