The 2010 ACM-ICPC Asia Chengdu Regional Contest 的几个题目

The 2010 ACM-ICPC Asia Chengdu Regional Contest 的几个题目

声明:本博菜,只做水。

题目网址:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3416
比赛网址:
http://acm.zju.edu.cn/onlinejudge/showContestProblems.do?contestId=319

【Problem C】
 水题,直接按题目意思写即可。

#include<stdio.h>
#define  MAXN 210
int a[MAXN] , b[MAXN] ;


int bit( int x , int i){
    
return (x)&(1<<i) ? 1 : 0 ;
}


int f(int x ,int y){
    
int i , cnt = 0 ;
    
for(i = 0 ; i < 30 ; ++ i)
        
if(bit(x ,i) != bit(y , i))  ++ cnt ;
    
return cnt ;
}


int main(){
    
int n, m , test , ans , val , tr , i , j ;
    scanf(
"%d" ,&test);
    
while(test -- ){
             scanf(
"%d%d" , &n , &m);
             
for(i = 0 ; i < n ; ++ i)  scanf("%d" , &a[i]);
             
for(i = 0 ; i < m ; ++ i)  scanf("%d" , &b[i]);
             
for(j = 0 ; j < m ; ++ j){
                   val 
= 1000009 ;  ans = 100 ;
                   
for(i = 0 ; i < n ; ++ i)
                   
{
                       tr 
= f(a[i] , b[j]);
                       
if(tr < ans ){
                         ans 
= tr ;  val =  a[i] ;
                       }
else if(tr == ans){
                         val 
=  val < a[i] ? val : a[i] ;
                       }

                   }

                   printf(
"%d\n" , val);
             }

    }

    
return 0 ;
}

【Problem E】
 题目并不难:以相同的命令控制两个迷宫,求最少命令序列。
 思路也容易想到,把两个球的坐标看成一个状态就行了,其余就是简单的广搜了。
 问题是: 这题有很多小限制,例如最小字典序,节点的生成。非常考验编程的基本功。
 可惜,我好像弄了2-3个小时。

#include<iostream>
#include
<memory>
#include
<cstdio>
#include
<cstring>
#include
<cstdlib>
#include
<cmath>
#include
<queue>
#define  INF  (1<<29)
using namespace std ;

struct node{
     
int x0 , y0 , x1 ,y1 ;

}
;
node  start , end ;
char  cmd[] = "DLRU" ;
int dx[] = {1 , 0 , 0 , -1} ; 
int dy[] = {0 , -1 , 1 , 0} ;

// 数组t[]是为了便于找到方向信息在二进制中的位置 
int t[]  = {1 , 0 , 2 , 3 } ; 
int  bd0[6][6] , bd1[6][6];
int  prev[1300] ,  mov[1300] ;  // prev[i] 表示状态 i 的父亲节点 ,mov[i] 表示从状态 prev[i] 到 i 的操作。 


// 将状态压缩成一个数字 , 便于处理 
inline int  hash(node a){
         
return a.x0 * 216 + a.y0 * 36 + a.x1 * 6 + a.y1 ;
}

inline  
int bit(int x ,int i){
        
return  x &(1<<i) ?  1 : 0 ;
}

inline  
int IsOut(int x ,int y){
        
return x<0||y<0||x>=6||y>=6;
}

inline  
int IsEnd(node a){
        
return  hash(a) == hash(end);
}


//初始化找到  起始状态 和  终点状态 
void  init(){
      
int i , j ; 
      
for(i = 0 ; i < 6 ; ++ i)
          
for(j = 0 ; j < 6 ; ++ j){
              
if(1 == bit(bd0[i][j], 5))  start.x0 = i , start.y0 = j ;
              
if(1 == bit(bd0[i][j], 6))  end.x0 = i   ,   end.y0 = j ;
              
if(1 == bit(bd1[i][j], 5))  start.x1 = i , start.y1 = j ;
              
if(1 == bit(bd1[i][j], 6))  end.x1 = i   ,   end.y1 = j ;
          }

}
 

//构造字典序最小的解 
void MakeSolution(int val){
     
if(prev[val] != INF){
           MakeSolution(prev[val]) ;
           printf(
"%c" , cmd[mov[val]]);
     }
  
}


void Run(){
     
int i , cx0 , cy0 , cx1 , cy1 ,nx0 ,ny0 ,nx1 , ny1 , val ; 
     node cur  , nxt ;
     queue
<node>  Q ;
     init();
     
if(IsEnd(start))  return ;
     memset(prev , 
-1 ,sizeof(prev));     
     prev[ hash(start) ] 
= INF ; 
     Q.push(start);
     
while(!Q.empty()){
            cur 
= Q.front() ;  Q.pop();
            cx0 
= cur.x0 , cy0 = cur.y0 , cx1 = cur.x1 , cy1 = cur.y1 ; 
            
// 由于要求构造的解满足字典序最小,所以应该选择以 < D , L , R , U>这种顺序拓展。 
            for(i = 0 ; i < 4 ; ++ i)
                
if(!bit(bd0[cx0][cy0],t[i])||!bit(bd1[cx1][cy1] ,t[i])){
                       nx0 
= cx0 + dx[i] , ny0 = cy0 + dy[i] ; 
                       nx1 
= cx1 + dx[i] , ny1 = cy1 + dy[i] ; 
                       
//生成 next 这个儿子节点 , 碰壁时则不动 
                       if(!bit(bd0[cx0][cy0] , t[i])){
                            nxt.x0 
= nx0 , nxt.y0 = ny0 ;
                       }
 else {
                            nxt.x0 
= cx0 , nxt.y0 = cy0 ;
                       }
  
                       
if(!bit(bd1[cx1][cy1] , t[i])){
                            nxt.x1 
= nx1 , nxt.y1 = ny1 ; 
                       }
else{
                            nxt.x1 
= cx1 , nxt.y1 = cy1 ; 
                       }

                       
if(IsOut(nxt.x0,nxt.y0)||IsOut(nxt.x1,nxt.y1))  continue ; // 判断出界 
                       if(!bit(bd0[nxt.x0][nxt.y0],4)||!bit(bd1[nxt.x1][nxt.y1],4)) continue ; // 判断是否为洞 
                       if(prev[val = hash(nxt)] != -1)  continue ;  // 判断是否重复 
                       prev[val] = hash(cur) ;  mov[val] = i ; 
                       
//终点状态 
                       if(IsEnd(nxt)){
                               MakeSolution(val);   
return ;
                       }

                       Q.push(nxt);
                }

     }

     printf(
"-1");
}


int main(){
    
int i ,j , tst  ; 
    scanf(
"%d" , &tst);
    
--tst ;
    
for(i = 0 ; i < 6 ; ++ i)
       
for(j = 0 ; j < 6 ; ++ j)
          scanf(
"%d" ,&bd0[i][j]);
    
while(tst--){
          
for(i = 0 ; i < 6 ; ++ i)
             
for(j = 0 ; j < 6 ; ++ j)
                 scanf(
"%d" ,&bd1[i][j]);
          Run();
          printf(
"\n") ;
          
for(i = 0 ; i < 6 ; ++ i)
             
for(j = 0 ; j < 6 ; ++ j)
                bd0[i][j] 
= bd1[i][j] ;
    }

    
return 0;
}





【Problem F】
 定义:
 F(x) = max( Si(x) ) , 其中 Si(x) = ai*x^2 + bi*x  + ci . 这里 0<=ai 。
 稍微观察一下,即可发现F(x)是一个纯单调函数或者单峰函数。速度三分法水.....
 只是这里特别注意精度问题,经测试,当 eps > 1e-9 时,果断WA 。

#include<stdio.h>
#define  MAXN 10005
#define  EPS  (1e-10)
#define  INF  (1e100)

typedef 
struct{
     
double a ,b ,c ;
}
node;

node  e[MAXN] ;
int   n ;

double f(node t , double x){
       
return  t.a * x * x + t.b * x + t.c ;
}


int sgn(double x){
    
return (x>EPS) - (x<-EPS) ;
}


double can(double x){
       
double maxval = -INF , tr ;
       
int i ;
       
for(i = 0 ; i <n ; ++i)
       
{
          tr 
= f(e[i] , x);
          
if(tr > maxval)
              maxval 
= tr ;
       }

       
return maxval ;
}


double Min(double x, double y){
       
return x < y ?  x :y ;
}


double Run(){
      
double ans , t1 , t2 , t3 ,t4 ;
      
int i ;
      t1 
= 0.0 ;  t4 = 1000.0 ;
      
for(i = 0 ; i < 100 ; ++i){
             t2 
= (t4 - t1)/3.0 + t1 ;
             t3 
= (t4 - t1)/1.5 + t1 ;
             
if(can(t2) < can(t3))
                  t4 
= t3 ;
             
else
                  t1 
= t2 ;
             
if(!sgn(t1-t4)) break ;
      }

      
return can(t1) ;
}




int main(){
    
int  test ,i;
    
int a , b , c;
    scanf(
"%d" , &test);
    
while(test -- ){
       scanf(
"%d",&n);

       
for(i = 0 ; i < n ; ++i){
           scanf(
"%d%d%d" ,&a ,&b , &c) ;
           e[i].a 
= (double)a ;
           e[i].b 
= (double)b;
           e[i].c 
= (double)c;
       }

       printf(
"%0.4lf\n" ,Run());
    }


    
return 0;
}
【Problem G】
 常用思路: 2_SAT + 二分。
 这里 2_SAT模型中的 <a , ~a> 对应于 x[i] 取 0 或者 1 。
 互斥条件是 : x[a[dep]] + x[b[dep]] == c[dep] 。
 图中的点数为 2*n , 边数最多为 m 。 复杂度 O(m*log(m))。
 对答案进行二分即可。


#include<iostream>
#include
<stdio.h>
#include
<cstring>
#define  MAXN  405
#define  MAXM 10005
using namespace std ;

bool gh[MAXN][MAXN] ;
int  N , Ecnt , a[MAXM] , b[MAXM] ,c[MAXM];

void build(int  MaxDepth){
     
int i , j , dep , x, y;
     
for(i = 0 ; i < 2*N ; ++ i)
                 
for(j = 0 ; j < 2*N ; ++ j)
                       gh[i][j] 
= 0 ;
     
for(dep = 0 ; dep < MaxDepth ; ++ dep){
                 x 
= a[dep] , y = b[dep] ;
                 
if(0 + 0 == c[dep])  gh[2*x][2*y+1= gh[2*y][2*x+1= 1 ;
                 
if(0 + 1 == c[dep])  gh[2*x][2*y] = gh[2*y+1][2*x+1= 1 ;
                 
if(1 + 0 == c[dep])  gh[2*x+1][2*y+1= gh[2*y][2*x] = 1 ;
                 
if(1 + 1 == c[dep])  gh[2*x+1][2*y] = gh[2*y+1][2*x] = 1 ;
     }

}


int bcnt , idx ,top , stk[MAXN] ,instk[MAXN] , dfn[MAXN] , low[MAXN] ,bel[MAXN] ;

void Tarjan(int x){
     
int  y ;
     low[x] 
= dfn[x] = ++idx ;
     instk[x] 
= 1 ;  stk[top++= x ;
     
for(y = 0 ; y <2*N ; ++y)
       
if(gh[x][y]){
              
if(dfn[y] == -1){
                   Tarjan(y); 
                   low[x] 
= min(low[x] , low[y]);
              }
else if(instk[y]){
                   low[x] 
= min(low[x] , dfn[y]);
              }

       }

     
if(low[x] == dfn[x]){
         
++bcnt ;
       
do{
         y 
= stk[--top] ; instk[y] = 0 ; bel[y] = bcnt ;
       }
while(y!=x);
     }

}


bool check(int mid){
     
int i ;
     build(mid);
     bcnt 
= idx = top = 0 ;
     
for(i = 0 ; i < 2*N; ++i){
          dfn[i] 
= -1 , instk[i] = 0 ;
     }

     
for(i = 0 ; i < 2*N ; ++ i)
        
if(dfn[i] == -1)  Tarjan(i);
     
for(i = 0 ; i < N ; ++ i)
         
if(bel[2*i] == bel[2*i+1]) return false ;
     
return true;
}


int main(){
    
int test , i , j , x, y ; 
    scanf(
"%d" ,&test);
    
while(test--){
           scanf(
"%d%d" ,&N ,&Ecnt);
           
for(i = 0 ; i < Ecnt ; ++ i)
                scanf(
"%d%d%d" , &a[i] ,&b[i] , &c[i]);
           
int l , r , mid , ans ; 
           l 
= ans = 1 , r = Ecnt ; 
           
while(l <= r){
                mid 
= (l + r ) / 2 ;
                
if(check(mid)){
                    ans 
= mid , l = mid + 1 ;
                }
else{
                    r 
= mid - 1 ;
                }

           }

           printf(
"%d\n" ,ans);
    }

    
return 0 ;
}

【Problem J】
 最大费用最大流  or 最佳匹配算法 ( KM 算法)。
 设标准答案串为 T , 学生答案串为S 。
 算法设计:
 (1). 分别统计<t,s>的对数为f(t,s),其中 t 属于 T , s 属于 S 。
 (2). X = {A,B,..,Z} , Y = {A,B,..,Z}.
      以 X 集和 Y 集建一个二分图。
      对每一对<t,s> 从 X 中的字母 t 连一条边至 Y 集中的s , 边权为 f(t,s) 。
 (3). 求二分图的最优匹配 ( KM算法 or 最大费用最大流 ) 即答案。
 

#include<iostream>
#include
<stdio.h> 
#include
<queue>
#define  INF  1<<29
#define  MAXN 60
#define  MAXS 10005
using namespace std; 

typedef 
struct{
       
int  y , c , cost , next ;
}
node ;
node  e[MAXN
*MAXN]  ;
int   es , hd[MAXN] , S , T,Vcnt ;
int   cnt[MAXN][MAXN];
int   TT[MAXS] , SS[MAXS] ;
int   dist[MAXN] ,vis[MAXN] ,prev[MAXN] , pos[MAXN] ;

void ins(int x , int y ,int c ,int cost){
     e[es].y 
= y , e[es].c = c , e[es].cost = cost , e[es].next = hd[x] , hd[x] = es ++;
     e[es].y 
= x , e[es].c = 0 , e[es].cost = -cost ,e[es].next = hd[y] , hd[y] = es ++;
}


void Build(){
     
int i , j , k ;
     es 
= 0 ;  S =  53 ; T = 54 ;   Vcnt = 54 ;
     
for(i = 1 ; i <= Vcnt ; ++ i)   hd[i] = -1 ;
     
for(i = 1 ; i <= 26 ; ++i)
        
for(j = 1 ; j<=26 ; ++j)
          
if(cnt[i][j]!=0)
             ins(i , 
26 + j , 1 , -cnt[i][j]);
     
for(i = 1 ; i <= 26 ; ++i){
         ins(S , i , 
1 , 0 );
         ins(
26+i ,T , 1 , 0);
     }

}


int Spfa(){
     
int i , j , k , x ,y  ;
     queue
<int> Q ;
     
for(i = 1 ; i<=Vcnt ; ++ i) {
         prev[i] 
= -1 , vis[i] = 0 , dist[i] = INF;
     }

     Q.push(S) ;  dist[S] 
= 0 ;  vis[S] = 1 ;
     
while(!Q.empty()){
           x 
= Q.front() , Q.pop() ;   vis[x] = 0 ;
           
for(i = hd[x] ; i!=-1 ; i=e[i].next){
                y 
= e[i].y ;
                
if(e[i].c && dist[y] > dist[x] + e[i].cost){
                     dist[y] 
= dist[x] + e[i].cost ;
                     prev[y] 
= x ;  pos[y] = i ;
                     
if(vis[y] == 0){
                         vis[y] 
= 1 ;  Q.push(y);
                     }

                }

           }

     }

    
return prev[T] != -1 ;
}


int  MinCost(){
     
int   res = 0  , del , i , j ,k , u, v;
     
while(Spfa()){
          del 
= INF ;
          
for(u = T ; u!=S ; u = prev[u])  del = min(del , e[pos[u]].c);
          
for(u = T ; u!=S ; u = prev[u])
             e[pos[u]].c 
-= del , e[pos[u]^1].c += del ;
          res 
+= del * dist[T]  ;
     }

     
return res ;
}


int main(){
    
int cs , test , N ,K , M ,i ,j , ans;
    
char  ss[3];
    scanf(
"%d" ,&test);
    
while(test--){
         scanf(
"%d%d%d" , &N , &K ,&M);
         
for(i = 0 ; i < N ; ++ i){
               scanf(
"%s" , ss);
               TT[i] 
= ss[0- 'A' + 1;
         }

         
for(cs = 0 ; cs < M ; ++ cs){
               
for(i = 0 ; i < N ; ++ i)
                  scanf(
"%s" ,ss) , SS[i] = ss[0]-'A' + 1  ;
               
for(i = 1 ; i <= Vcnt; ++ i)
                  
for(j = 1 ; j <= Vcnt ; ++ j)
                  cnt[i][j] 
= 0 ;
               
for(i = 0 ; i < N ; ++ i)
                  
++ cnt[TT[i]][SS[i]] ;
               Build();
               ans 
= -MinCost();
               printf(
"%0.4lf\n" , (double)ans/(double)N);
         }


    }

    
//while(getchar());
    return 0 ;
}


你可能感兴趣的:(The 2010 ACM-ICPC Asia Chengdu Regional Contest 的几个题目)