題目大意
有 個布爾變量 ,在一組約束下恰好有三種賦值方式。
約束是形如 這樣, 可以是 , 可以是 。
現給出這三種賦值方式,請構造出一組約束。
,你構造的約束數量
題解
紀念一下已經傻掉的自己
因爲這個題目模型很 2-sat,所以上來就在想 tarjan,沒想到最後居然是這麼 sb 的做法。。
首先,如果一個變量在三次賦值中都是相同的,那它是常值變量,可以一條約束直接解決掉。(若 ,則 ;若 ,則 )
然後,合併本質相同的變量。即,若 與 取值完全相同或完全相反,都可以用兩條約束解決掉。
那麼,最後一定只能剩下兩個變量。
這是因爲,由於合併了本質相同的變量,因此本質不同的情況最多隻有 4 種,而其中有一種是常值的情況,因此最多隻有 3 種。但是如果有 3 種的話,是無解的,因此最多 2 種。而合法的數據又不會只有 1 種,因此只能是 2 種。
剩下的這兩個變量可以一條約束解決掉。
所以最後在 條約束下就解決了。
代碼
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
int n,a[maxn][4],m;
pair<pair<int,int>,pair<int,int>> ans[maxn];
int main()
{
scanf("%d",&n);
fo(j,1,3)
fo(i,1,n) scanf("%d",&a[i][j]);
int cnt=0, w1, w2;
fo(i,1,n) if (a[i][1]==a[i][2] && a[i][1]==a[i][3])
{
ans[++m]=make_pair(make_pair(i,a[i][1]),make_pair(i,a[i][1]^1));
} else
{
bool idp=1;
fo(j,1,i-1) if (a[i][1]==a[j][1] && a[i][2]==a[j][2] && a[i][3]==a[j][3])
{
idp=0;
ans[++m]=make_pair(make_pair(j,0),make_pair(i,0));
ans[++m]=make_pair(make_pair(j,1),make_pair(i,1));
break;
} else if (a[i][1]!=a[j][1] && a[i][2]!=a[j][2] && a[i][3]!=a[j][3])
{
idp=0;
ans[++m]=make_pair(make_pair(j,0),make_pair(i,1));
ans[++m]=make_pair(make_pair(j,1),make_pair(i,0));
break;
}
if (idp)
{
++cnt;
if (cnt==1) w1=i; else w2=i;
}
}
if (cnt!=2) puts("-1"); else
{
int df;
if (a[w1][1]!=a[w1][2] && a[w1][1]!=a[w1][3]) df=1;
else if (a[w1][2]!=a[w1][1] && a[w1][2]!=a[w1][3]) df=2;
else df=3;
ans[++m]=make_pair(make_pair(w1,a[w1][df]^1),make_pair(w2,a[w2][df]^1));
printf("%d\n",m);
fo(i,1,m)
{
if (ans[i].first.second) putchar('!');
printf("x%d -> ",ans[i].first.first);
if (ans[i].second.second) putchar('!');
printf("x%d\n",ans[i].second.first);
}
}
}