zoukankan      html  css  js  c++  java
  • 洛谷P4171

    题目很长,废话很多,但是很板

    Description

    给出 (n) 个数,(m) 个条件

    每个数有两种类型,只能选择其中一种类型

    每组条件包含两个,每个要求一种类型的数字

    问这 (n) 个数能不能符合所有的条件

    Solution

    问所有数字能否满足所有的条件,显然是适定性问题

    首先要明确一点,每组的条件至少满足一个,也就是说可以全部满足

    但要想让答案最优,选择满足其中一个就好,因为这样能用更少的数字满足更多的条件

    那每次两个条件满足其一,显然选择 2-SAT 求解

    考虑如何建边

    由于题目中有 每种材料只能做一种菜式 的限制,所以我们对于每组条件的每一个,向另一种条件的对立事件建边

    假设 (a,b) 处于同一组条件,(A,B) 分别是他们的另一种类型

    那我们建有向边 ((a,B))((b,A)),表示选择 (a) 必须选择 (B),选择 (b) 必须选择 (A),同时满足上面的最优性说明

    之后跑强连通分量,判断在同一个 SCC 内,是否有两个条件处于同一组,无则成立,有则不成立

    Code

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #define maxn 100100
    #define rr register 
    #define INF 0x3f3f3f3f
    //#define int long long
    #define debug cout<<"lkp ak ioi"<<endl
    
    using namespace std;
    
    string s1,s2;
    bool vis[maxn],flag;
    int k,n,m,top,tot,t,cnt; 
    int low[maxn],head[maxn],dfn[maxn],num[maxn],zhan[maxn];
    struct edge{int fr,to,nxt;}e[maxn<<1];
    
    inline int read(){
        int s=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
        return s*w;
    }
    
    void add(int fr,int to){
        e[++tot].to=to;e[tot].fr=fr;
        e[tot].nxt=head[fr];head[fr]=tot;
    }
    
    int Turn(string s){
        int ans=0;
        for(int i=1;i<s.length();i++)
    	ans*=10,ans+=s[i]-'0';	
        if(s[0]=='h') return ans;
        return ans+n;
    }
    
    int No(string s){
        int ans=0;
        for(int i=1;i<s.length();i++)
            ans*=10,ans+=s[i]-'0';	
        if(s[0]=='h') return ans+n;
        return ans;
    }
    
    void clear(){
        tot=top=t=cnt=flag=0;
        memset(dfn,0,sizeof dfn);
        memset(low,0,sizeof low);
        memset(num,0,sizeof num);
        memset(vis,0,sizeof vis);
        memset(head,0,sizeof head);
    }
    
    void tarjan(int u){
        dfn[u]=low[u]=++cnt;
        vis[u]=1;zhan[++top]=u;
        for(int i=head[u];i;i=e[i].nxt){
            int to=e[i].to;
            if(!dfn[to]) tarjan(to),low[u]=min(low[u],low[to]);
            else if(vis[to]) low[u]=min(low[u],dfn[to]);
        }
        if(dfn[u]==low[u]){
            int pre=zhan[top--];
            num[pre]=++t;vis[pre]=0;
            while(pre!=u){
                pre=zhan[top--];
                num[pre]=t;vis[pre]=0;
            }
        }
    }
    
    int main(){
        k=read();
        while(k--){
            clear();n=read();m=read();
            for(int i=1;i<=m;i++){
                cin>>s1>>s2;
                add(Turn(s1),No(s2));
                add(Turn(s2),No(s1));
            }
            for(int i=1;i<=n*2;i++)if(!dfn[i])tarjan(i); 
            for(int i=1;i<=n;i++)if(num[i]==num[i+n]){printf("BAD
    ");flag=1;break;}
            if(!flag) printf("GOOD
    ");
        }
        return 0;
    } 
    
  • 相关阅读:
    文件的操作
    encode,decode,str,bytes
    字符串操作
    suse12安装mysql8.16
    VMware配置共享磁盘安装RAC
    Linux过滤文本并显示过滤文字的上下文
    Linux服务器卸载mysql指南
    oracle 各版本各日志存放位置
    impdp按用户导入
    数据泵expdp定时备份
  • 原文地址:https://www.cnblogs.com/KnightL/p/14365855.html
Copyright © 2011-2022 走看看