C++题解:慈善晚会

 经典题目

注:As the time goes by,I have turned middle school student.So I'm short of time.From now on, I will not write comments in the code. It may not be satisfaction with you.Sorry.

目录

题目 

输入格式

输出格式

题解:


题目 

  • 1000ms
  • 131072K

蒜头君热心公益,他想要在近期举办一场慈善晚宴,准备邀请一些社会名流前来,但社会名流都是成双入对的,蒜头君自己是单身汉,所以他只想每一对夫妻来一个人,社会名流之间的关系比较复杂,有些人之间关系不好,他们不想同时出现,当然夫妻之间不会是关系不好的,蒜头君想知道有没有一种方案使得每一对夫妻都有一个人参加晚宴。

输入格式

第一行两个整数 n,mn,m(1≤n≤104,1≤m≤105),表示社会名流夫妻数和关系不好的关系数;

接下来 mm 行,每行四个整数 A1,A2,C1,C2,每两个数之间用一个空格隔开,A1,A2 表示夫妻编号,编号从 0 开始,C1,C2 表示是夫妻之中的哪一个人,其中值为 0 时表示丈夫,值为 1 时表示妻子。

输出格式

输出一行,如果存在一种合适的方案,输出"YES",否则输出"NO"

格式说明

输出时每行末尾的多余空格,不影响答案正确性

输入、输出要求

要求使用「文件输入、输出」的方式解题,输入文件为 charitable.in,输出文件为 charitable.out

样例输入

2 1
0 1 0 1

样例输出

YES

题目解释:A1 A2表示有两对夫妻A1和A2之间有人有矛盾,C1表示有矛盾的人是夫妻A1中的夫还是妻,C2表示有矛盾的人是夫妻A2中的夫还是妻


题解:

知识点:2-SAT问题

分析:

这是一个非常经典的 2-SAT 问题,一队夫妻可以看作一个 xi​=0/1 的 01 变量。也就是说,这里的2-SAT问题是将true和false两大集合变成了妻子和丈夫两大集合

这道题是用 2-SAT 描述“反对”关系,也就是:

两人关系不好,就把一个人向另一个人的伴侣连一条边(即一个人去了,与他关系不好的人就一定不能去,由题意得与他关系不好的人的伴侣就必须要去,“否则会吃饱【DOGE】”),然后进行 2-SAT,先尝试选丈夫,不行的话就选妻子,都不行的话就是"NO",最后每一对都能选出一个人的话就是"YES"

如果你不会基础的 2-SAT 模板,可以去相关的课程学习,或者去网上搜索相关博客。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
const int N=2e4+5,M=2e5+5;
int n,m;
int e[M],ne[M],h[N],idx;
int selected[N],c,S[N];
inline void c_plus(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
}
inline void init(){
    idx=0;
    memset(h,-1,sizeof(h));
}
inline void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
bool dfs(int u){
    if (selected[u^1]){
        return false;
    }
    if (selected[u]){
        return true;
    }
    selected[u]=true;
    S[c++]=u;
    for (int i=h[u];~i;i=ne[i]){
        int v=e[i];
        if (!dfs(v)){
            return false;
        }
    }
    return true;
}
bool Two_SAT(){
    for (int i=0;i<(n<<1);i+=2){
        if (!selected[i] && !selected[i+1]){
            c=0;
            if (!dfs(i)){
                while (c>0){
                    selected[S[--c]]=false;
                }
                if (!dfs(i+1)){
                    return false;
                }
            }
        }
    }
    return true;
}
int main(){
    freopen("charitable.in","r",stdin);
    freopen("charitable.out","w",stdout);
    c_plus();
    init();
    cin>>n>>m;
    while (m--){
        int a1,a2,c1,c2;
        cin>>a1>>a2>>c1>>c2;//a为a1夫妻,b为a2夫妻
        int a[2]={(a1<<1),(a1<<1)+1},b[2]={(a2<<1),(a2<<1)+1};
        add(a[c1],b[c2^1]);
        add(b[c2],a[c1^1]);
    }
    if (Two_SAT()){
        puts("YES");
    }else{
        puts("NO");
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!对于扫雷游戏的题解,我可以给你一些思路和代码示例。首先,你需要了解扫雷游戏的规则和要求。接下来,你可以使用C++语言来实现游戏逻辑和界面。 下面是一个简单的扫雷游戏的C++代码示例: ```cpp #include <iostream> #include <vector> #include <random> using namespace std; class MinesweeperGame { private: int rows; int cols; vector<vector<char>> board; vector<vector<bool>> revealed; vector<pair<int, int>> directions = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; public: MinesweeperGame(int m, int n, int mineCount) { rows = m; cols = n; board.resize(rows, vector<char>(cols, ' ')); revealed.resize(rows, vector<bool>(cols, false)); placeMines(mineCount); calculateNumbers(); } void printBoard() { cout << " "; for (int j = 0; j < cols; j++) { cout << j << " "; } cout << endl; for (int i = 0; i < rows; i++) { cout << i << " |"; for (int j = 0; j < cols; j++) { cout << board[i][j] << "|"; } cout << endl; } } bool isGameOver() { for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (board[i][j] == 'M' && revealed[i][j]) { return true; } } } return false; } void reveal(int row, int col) { if (row < 0 || row >= rows || col < 0 || col >= cols || revealed[row][col]) { return; } revealed[row][col] = true; if (board[row][col] == 'M') { return; } if (board[row][col] == '0') { for (auto dir : directions) { reveal(row + dir.first, col + dir.second); } } } private: void placeMines(int mineCount) { random_device rd; mt1

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值