【AHOI2013复仇】SCOI2008 天平

原题地址
本题就是,有N个变量,其取值只可能有三种:1、2、3。现在已知它们之间的一些大小关系,求有多少对变量(I, J)满足(I的值+J的值)一定>或=或<(A的值+B的值),A、B是指定的两个变量,且I、J、A、B互不相同。
首先,对于值相等的变量,直接建出无向图,按连通块缩点,再考虑大于/小于关系,如果I的值大于J则在I所在连通块与J所在连通块之间连一条有向边(从I到J)……这样,凡是既有前趋,又有后继的点(缩成的点,下同),其值只能是2,它的所有前趋的值只能是3,所有后继的值只能是1。除此以外,木有其它办法能唯一确定某个变量的值。

接下来最关键的一步——枚举I、J以及I、J、A、B的值,判断是否合法:
(1)如果某个变量的值已确定,且与枚举的值不同,不合法;
(2)如果某个变量有前趋,那么它的值就不能是3;如果有后继,那么它的值就不能是1;
(3)(这是最容易搞疵的)对于I、J、A、B之间已知的大小关系,要判断是否能全部满足, 注意这里的I、J、A、B是指缩成以后的点,而不是原来的变量(本沙茶一开始用原来的变量判断,结果WA了,后来把数据弄下来看了一下,是这里搞疵了囧……不过只跪了2个点,总共20个点),因为有可能它们本身之间木有给出关系,但那些与它在一个连通块中的(即与它值相等)的变量之间给出了关系。

至于枚举……由于本题数据小,只需要暴力枚举就行了囧……

本题的启示:考虑问题要周全,要设法考虑到所有情况。

代码:
#include  < iostream >
#include 
< stdio.h >
#include 
< stdlib.h >
#include 
< string .h >
using   namespace  std;
#define  re(i, n) for (int i=0; i<n; i++)
#define  re1(i, n) for (int i=1; i<=n; i++)
#define  re2(i, l, r) for (int i=l; i<r; i++)
#define  re3(i, l, r) for (int i=l; i<=r; i++)
#define  rre(i, n) for (int i=n-1; i>=0; i--)
#define  rre1(i, n) for (int i=n; i>0; i--)
#define  rre2(i, r, l) for (int i=r-1; i>=l; i--)
#define  rre3(i, r, l) for (int i=r; i>=l; i--)
#define  ll long long
const   int  MAXN  =   61 , MAXM  =   8000 , INF  =   ~ 0U   >>   2 ;
struct  edge {
    
int  a, b, pre, next;
} _E[MAXM 
+  MAXM  +  MAXN], E[MAXM  +  MAXM  +  MAXN], E2[MAXM  +  MAXM  +  MAXN];
int  n, _m, m, No1, No2;
int  n0, A[MAXN][MAXN], A2[MAXN][MAXN], Q[MAXN], D[MAXN], W[MAXN], ST[MAXN][MAXN], res1  =   0 , res2  =   0 , res3  =   0 ;
bool  vst[MAXN];
char  ss[MAXN  +   1 ];
void  init_d0()
{
    re(i, n) _E[i].pre 
=  _E[i].next  =  i;
    
if  (n  &   1 ) _m  =  n  +   1 else  _m  =  n;
}
void  init_d()
{
    re(i, n0) E[i].pre 
=  E[i].next  =  E2[i].pre  =  E2[i].next  =  i; m  =  n0;
}
void  add_edge0( int  a,  int  b)
{
    _E[_m].a 
=  a; _E[_m].b  =  b; _E[_m].pre  =  _E[a].pre; _E[_m].next  =  a; _E[a].pre  =  _m; _E[_E[_m].pre].next  =  _m ++ ;
    _E[_m].a 
=  b; _E[_m].b  =  a; _E[_m].pre  =  _E[b].pre; _E[_m].next  =  b; _E[b].pre  =  _m; _E[_E[_m].pre].next  =  _m ++ ;
}
void  add_edge( int  a,  int  b)
{
    E[m].a 
=  a; E[m].b  =  b; E[m].pre  =  E[a].pre; E[m].next  =  a; E[a].pre  =  m; E[E[m].pre].next  =  m;
    E2[m].a 
=  b; E2[m].b  =  a; E2[m].pre  =  E2[b].pre; E2[m].next  =  b; E2[b].pre  =  m; E2[E2[m].pre].next  =  m ++ ;
}
void  init()
{
    scanf(
" %d%d%d " & n,  & No1,  & No2); init_d0(); No1 -- ; No2 -- ;
    re(i, n) {
        scanf(
" %s " , ss);
        re(j, n) 
if  (i  !=  j) {
            
if  (ss[j]  ==   ' ? ' ) A[i][j]  =   0 ;
            
else   if  (ss[j]  ==   ' + ' ) A[i][j]  =   1 ;
            
else   if  (ss[j]  ==   ' - ' ) A[i][j]  =   2 else  {A[i][j]  =   3 ; add_edge0(i, j);}
        }
    }
}
void  prepare()
{
    re(i, n) re(j, n) 
if  (i  !=  j) {
        
if  (A[i][j]  ==   1 ) A[j][i]  =   2 ;
        
if  (A[i][j]  ==   2 ) A[j][i]  =   1 ;
        
if  (A[i][j]  ==   3 ) A[j][i]  =   3 ;
    }
    re(i, n) {W[i] 
=   0 ; vst[i]  =   0 ;}  int  x, y; n0  =   0 ;
    re(i, n) 
if  ( ! vst[i]) {
        vst[i] 
=   1 ; Q[ 0 =  i; D[i]  =  n0;
        
for  ( int  front = 0 , rear = 0 ; front <= rear; front ++ ) {
            x 
=  Q[front];
            
for  ( int  p = _E[x].next; p  !=  x; p = _E[p].next) {
                y 
=  _E[p].b;
                
if  ( ! vst[y]) {vst[y]  =   1 ; Q[ ++ rear]  =  y; D[y]  =  n0;}
            }
        }
        n0
++ ;
    }
    init_d(); re(i, n0) re(j, n0) A2[i][j] 
=   0 ;
    re(i, n) re(j, n) 
if  (D[i]  !=  D[j]) {
        
if  (A[i][j]  ==   1 ) add_edge(D[i], D[j]);  else   if  (A[i][j]  ==   2 ) add_edge(D[j], D[i]);
    }
    re(i, n) re(j, n) 
if  (i  !=  j  &&  A[i][j]) A2[D[i]][D[j]]  =  A[i][j];
}
void  solve()
{
    
int  x; re(i, n) re(j, n) ST[i][j]  =   0 ;
    re(i, n0) 
if  (E[i].next  !=  i  &&  E2[i].next  !=  i) {
        W[i] 
=   2 ;
        
for  ( int  p = E[i].next; p  !=  i; p = E[p].next) {
            x 
=  E[p].b; W[x]  =   1 ;
        }
        
for  ( int  p = E2[i].next; p  !=  i; p = E2[p].next) {
            x 
=  E2[p].b; W[x]  =   3 ;
        }
    }
    
int  d1  =  D[No1], d2  =  D[No2], di, dj;
    re(i, n) re2(j, i
+ 1 , n)  if  (i  !=  No1  &&  i  !=  No2  &&  j  !=  No1  &&  j  !=  No2) {
        di 
=  D[i]; dj  =  D[j];
        re1(si, 
3 ) {re1(sj,  3 ) {re1(s1,  3 ) {re1(s2,  3 ) {
            
if  (W[di]  &&  si  !=  W[di])  continue ;
            
if  (W[dj]  &&  sj  !=  W[dj])  continue ;
            
if  (W[d1]  &&  s1  !=  W[d1])  continue ;
            
if  (W[d2]  &&  s2  !=  W[d2])  continue ;
            
if  (E[di].next  !=  di  &&  si  ==   1 continue ;
            
if  (E2[di].next  !=  di  &&  si  ==   3 continue ;
            
if  (E[dj].next  !=  dj  &&  sj  ==   1 continue ;
            
if  (E2[dj].next  !=  dj  &&  sj  ==   3 continue ;
            
if  (E[d1].next  !=  d1  &&  s1  ==   1 continue ;
            
if  (E2[d1].next  !=  d1  &&  s1  ==   3 continue ;
            
if  (E[d2].next  !=  d2  &&  s2  ==   1 continue ;
            
if  (E2[d2].next  !=  d2  &&  s2  ==   3 continue ;
            
if  (A2[di][dj]  ==   1   &&  si  <=  sj)  continue ;
            
if  (A2[di][dj]  ==   2   &&  si  >=  sj)  continue ;
            
if  (A2[di][dj]  ==   3   &&  si  !=  sj)  continue ;
            
if  (A2[di][d1]  ==   1   &&  si  <=  s1)  continue ;
            
if  (A2[di][d1]  ==   2   &&  si  >=  s1)  continue ;
            
if  (A2[di][d1]  ==   3   &&  si  !=  s1)  continue ;
            
if  (A2[di][d2]  ==   1   &&  si  <=  s2)  continue ;
            
if  (A2[di][d2]  ==   2   &&  si  >=  s2)  continue ;
            
if  (A2[di][d2]  ==   3   &&  si  !=  s2)  continue ;
            
if  (A2[dj][d1]  ==   1   &&  sj  <=  s1)  continue ;
            
if  (A2[dj][d1]  ==   2   &&  sj  >=  s1)  continue ;
            
if  (A2[dj][d1]  ==   3   &&  sj  !=  s1)  continue ;
            
if  (A2[dj][d2]  ==   1   &&  sj  <=  s2)  continue ;
            
if  (A2[dj][d2]  ==   2   &&  sj  >=  s2)  continue ;
            
if  (A2[dj][d2]  ==   3   &&  sj  !=  s2)  continue ;
            
if  (A2[d1][d2]  ==   1   &&  s1  <=  s2)  continue ;
            
if  (A2[d1][d2]  ==   2   &&  s1  >=  s2)  continue ;
            
if  (A2[d1][d2]  ==   3   &&  s1  !=  s2)  continue ;
            
if  (s1  +  s2  >  si  +  sj) x  =   1 ;
            
else   if  (s1  +  s2  ==  si  +  sj) x  =   2 else  x  =   3 ;
            
if  ( ! ST[i][j]) ST[i][j]  =  x;  else   if  (ST[i][j]  !=  x) {ST[i][j]  =   - 1 break ;}
        } 
if  (ST[i][j]  ==   - 1 break ;}  if  (ST[i][j]  ==   - 1 break ;}  if  (ST[i][j]  ==   - 1 break ;}
    }
    re(i, n) re2(j, i
+ 1 , n)  if  (ST[i][j]  ==   1 ) res1 ++ else   if  (ST[i][j]  ==   2 ) res2 ++ else   if  (ST[i][j]  ==   3 ) res3 ++ ;
}
void  pri()
{
    printf(
" %d %d %d\n " , res1, res2, res3);
}
int  main()
{
    init();
    prepare();
    solve();
    pri();
    
return   0 ;
}

你可能感兴趣的:(【AHOI2013复仇】SCOI2008 天平)