大比萨 题解(不用Tarjan)

tarjan做法:这个问题被称为 2-sat。2-sat 解法的主要思想是:将 ai=x 这个命题当成一个点,这个命题当成一个点,则总共有2n个点。每一组限制可以理解拆解为两个限制,若已知ai!=x,则aj=y。因此每个限制是一个“推理”关系:若某个点的命题成立,则另一个点的命题也成立。如果以此为基础建图,那么强连通分量的意义是:这个分量的命题要么都成立,要么都不成立。
通过这个图结构,可以求解出结果。

但这题可以暴力贪心。如果有人两个要求都不满足时,我们尽量满足每人的的条件一,如果满足不了条件一(在满足其他人条件时,这个要求被做了修改),那么就满足条件二。如果条件二也无法满足,则再去尝试条件一。(有可能别人要满足的一个条件和自己要满足的条件互相冲突,但可以自己换另一个条件而保证所有条件成立)

首先建立一个二维数组用来存储每个的要求(因为之后要循环判断多次每个人的条件),和一个数组来存储所有配料加或不加。做一个循环来判断每个人的要求,并作出修改。(要进行多次判断与修改,也就是要循环多次这个循环)最后进行一次判断,若每人的要求都满足了,就正常输出。否则输出“IMPOSSIBLE”

#include<bits/stdc++.h>
using namespace std;

int n,m,b[3][100005];//记录每个人的愿望要针对的食材
bool s[100005],a[3][100005],d[3][100005];
//s[i]表示每种调料要不要放
//a表示每个愿望针对的食材要不要
  
int main(){
  cin >> n >> m;
  for(int i=1; i<=n; i++){//输入
    char c;
    cin >> c;
    cin >> b[1][i];
    if(c=='+'){
      a[1][i]=true;
    }
    cin >> c;
    cin >> b[2][i];
    if(c=='+'){
      a[2][i]=true;
    }
  }
  for(int l=1; l<=500; l++)
    for(int i=1; i<=n; i++){
      if(s[b[1][i]]==a[1][i]||s[b[2][i]]==a[2][i]){
        
    }else{
      if(!d[1][i]){//修改希望1
          s[b[1][i]]=a[1][i];
          d[1][i]=true;//下次会修改希望2
        }
        else if(!d[2][i]){//修改希望2
          s[b[2][i]]=a[2][i];
          //d[2][i]=true;//运行这行并注释下一行会95分
          d[1][i]=false;//下次修改希望1
        }
        else{//没用
          cout << "IMPOSSIBLE";
          return 0;
        }
      }
      
    }
  for(int i=1; i<=n; i++){//进行判断
    if(s[b[1][i]]==a[1][i]||s[b[2][i]]==a[2][i]){
        
    }else{
      cout << "IMPOSSIBLE";
          return 0;
    }
  }
  for(int i=1; i<=m; i++){
    if(s[i]){
      cout << "+ ";
    }
    else{
      cout << "- ";
    }
  }

  return 0;
}

后记
糖果(洛谷有原题)也可以用这种暴力贪心的做法,但我wa了一个点,我同学拿了AC,本蒟蒻就不在这里献丑了

2 个赞

这题貌似是 2-SAT 模板题

2 个赞

哦,我不太知道

1 个赞

基本是一样的

1 个赞