Description
Input
Output
Sample Input
Sample Output
Data Constraint
Solution
(附:本人第 100 篇博文,为 OI 事业奋斗,多多支持~)。
这道题的题面让人感到云里雾里,但是经过仔细的抽丝剥茧之后就会发现这真“模型”。
首先, X 矩阵是由
Y 向量构造出来的: X[i][j]=y[i] xor y[j] 。所以当 X 矩阵的对角线上存在
1 时,就不合法了,输出“-1”(异或运算的性质)。又由于 X 矩阵的对称性,我们只需处理对角线上方的答案,最后乘2即可。
我们发现,如果每一位
A[i][j]=1 的话,因为 A || !X=!O ,所以要求 X[i][j]=1 。所以相当于 y[i]≠y[j] ,则点 i 向点
j 连一条无向边,表示点 i 和点j 为对立点。这样便构出了一张二分图(若有奇环则判为“-1”),用 Friend-Enemy 并查集 维护出联通块。
那么最后答案是所有联通块的 0 的个数乘
1 的个数 。为了保证答案最优,对于这些连通块,我们可以做一遍类似背包的 O(N2)DP :
设 F[i][j] 表示做到第 i 个连通块、
0 的个数为 j 的1 的最大个数 ,转移显然。由于 X 取过反 ,
1 的最大个数即为所求。又由于开始的状态有 1 ,会计算重复,我们减去算出的 连边条数(意义相同) 即可。
那么连边、DP复杂度相等,这样总时间复杂度即为
O(N2) 。
Code
#include<cstdio>
#include<cstring>
#define clr(x,y) memset(x,y,sizeof(x));
using namespace std;
const int N=1001;
int n,tot,num;
int first[N],next[N<<1],en[N<<1];
int f[N][N],g[N],h[N][2],fa[N];
bool judge;
bool a[N][N];
inline int read()
{
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
inline int max(int x,int y)
{
return x>y?x:y;
}
inline int get(int x)
{
if(fa[x]==x) return x;
return fa[x]=get(fa[x]);
}
inline void insert(int x,int y)
{
next[++tot]=first[x];
first[x]=tot;
en[tot]=y;
}
inline void init_link()
{
tot=num=0;
clr(first,0);clr(g,-1);clr(h,0);clr(f,-1);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
if(a[i][j])
{
insert(i,j);
insert(j,i);
int f1=get(i),f2=get(j);
if(f1!=f2) fa[f1]=f2;
}
}
inline void dfs(int x,int y)
{
h[num][g[x]]++;
for(int i=first[x];i;i=next[i])
if(en[i]!=y)
{
if(g[en[i]]==g[x])
{
judge=true;
return;
}
if(g[en[i]]!=-1) continue;
g[en[i]]=g[x]^1;
dfs(en[i],x);
if(judge) return;
}
}
inline void dp()
{
int ans=f[0][0]=0;
for(int i=1;i<=num;i++)
for(int j=0;j<=n;j++)
{
int x=h[i][0],y=h[i][1];
if(j>=x && f[i-1][j-x]!=-1) f[i][j]=max(f[i][j],f[i-1][j-x]+y);
if(j>=y && f[i-1][j-y]!=-1) f[i][j]=max(f[i][j],f[i-1][j-y]+x);
}
for(int j=0;j<=n;j++) ans=max(ans,f[num][j]*j);
printf("%d\n",(ans<<1)-tot);
}
inline void work()
{
n=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) a[i][j]=read();
for(int i=1;i<=n;i++)
if(a[i][i])
{
printf("-1\n");
return;
}
init_link();
for(int i=1;i<=n;i++)
if(get(i)==i)
{
judge=g[i]=0,num++;
dfs(i,0);
if(judge)
{
printf("-1\n");
return;
}
}
dp();
}
int main()
{
int T=read();
while(T--) work();
return 0;
}