2014 Multi-University Training Contest 1小记

来源:互联网 发布:石破天 武功 知乎 编辑:程序博客网 时间:2024/05/17 04:50

hdu  4862 网络流

给定n*m的矩阵,选<=k个起点 ,每个起点可以向右或向下跳任意步 ,花费是2点间的曼哈顿距离 。

 若2个格子的数字一样 ,则赚取格子上的数字的价值 ,遍历整个图的最小花费 。 每个点只经过一次。

若不能遍历则输出-1

最小K路径覆盖的模型,用费用流或者KM算法解决,构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,流量1,费用0,Y部有N*M个节点,每个节点向汇点连一条边,流量1,费用0,如果X部的节点x可以在一步之内到达Y部的节点y,那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量,流量1,再在X部增加一个新的节点,表示可以从任意节点出发K次,源点向其连边,费用0,流量K,这个点向Y部每个点连边,费用0,流量1,最这个图跑最小费用最大流,如果满流就是存在解,反之不存在,最小费用的相反数就是可以获得的最大能量

const int maxn = 5000 ;const int maxm = 50000 ;const int inf = 1000000000 ;struct Edge{       int v , f , w , next ;       Edge(){}       Edge(int _v , int _f , int _w , int _next):v(_v),f(_f),w(_w),next(_next){}};int  g[maxn + 10] ;Edge e[maxm + 10] ;int  source , meet ;int  id ;int  maxflow ;void  add(int u , int v  , int f , int w){      e[++id] = Edge(v , f , w , g[u]) ;      g[u] = id ;      e[++id] = Edge(u , 0 , -w , g[v]) ;      g[v] = id ;}queue<int> que ;bool in[maxn + 10] ;int  dist[maxn + 10] ;int  pv[maxn + 10] , pe[maxn + 10] ;int bfs(){     while(! que.empty()) que.pop() ;     que.push(source) ;     memset(dist , 63 , sizeof(dist)) ;     dist[source] = 0  ;     in[source] = 1 ;     while(! que.empty()){           int u = que.front() ; que.pop() ;           in[u] = 0 ;           for(int i = g[u] ; i ; i = e[i].next){                int  v = e[i].v ;                if(e[i].f > 0 && dist[u] + e[i].w < dist[v]){                      dist[v] = dist[u] + e[i].w ;                      pv[v] = u ;                      pe[v] = i ;                      if(! in[v]){                            in[v] = 1 ;  que.push(v) ;                      }                }           }     }     return  dist[meet] < inf  ;}int  augment(){     int u = meet  ;     int delta = inf ;     while(u != source){           delta = min(delta , e[pe[u]].f) ;           u = pv[u] ;     }     u = meet ;     while(u != source){           e[pe[u]].f -= delta ;           e[pe[u] ^ 1].f += delta ;           u = pv[u] ;     }     maxflow += delta ;     return dist[meet] * delta ;}int  mincostflow(){     int ans = 0 ;     while(bfs())  ans += augment() ;     return ans ;}void init(){     memset(g , 0 , sizeof(g)) ;     id = 1 ;}int   n ,  m  ;int   lable(int i , int j , int k){      return n*m*k + (i-1) * m + j ;}int   main(){      int  i , j ,  k , u , v ,  w , T = 1  , t ;      char  str[12][12] ;      cin>>t ;      while(t--){           scanf("%d%d%d" , &n , &m , &k)  ;           for(i = 1 ; i <= n ; i++) scanf("%s" , str[i] + 1) ;           init() ;           source = 2*n*m + 1 ;           meet = 2*n*m + 2 ;           for(i = 1 ; i <= n ; i++){               for(j = 1 ;  j <= m ; j++){                    u = lable(i , j , 0) ;                    add(source , u , 1 , 0) ;                    for(int d = j+1 ; d <= m ; d++){                         v = lable(i , d , 1) ;                         w = d - j - 1 ;                         if(str[i][j] == str[i][d]) w -= str[i][j] - '0' ;                         add(u , v , 1 , w) ;                    }                    for(int d = i+1 ; d <= n ; d++){                         v = lable(d , j , 1) ;                         w = d - i - 1 ;                         if(str[i][j] == str[d][j]) w -= str[i][j] - '0' ;                         add(u , v , 1 , w) ;                    }                    u = lable(i , j , 1) ;                    add(u , meet , 1 , 0) ;               }           }           u = 2*n*m + 3 ;           add(source , u , k , 0) ;           for(i = 1 ; i <= n ; i++){               for(j = 1 ; j <= m ; j++){                   v = lable(i , j , 1) ;                   add(u , v , 1 , 0) ;               }           }           maxflow = 0 ;           w = mincostflow() ;           if(maxflow == n*m)  printf("Case %d : %d\n" , T++ , -w) ;           else                printf("Case %d : -1\n" , T++) ;      }      return 0 ;}


hdu  4865  dp 

dp[i][j]  : 第i天,天气为j的最大概率。 那么第i天的天气为 dp[i][0] , dp[i][1] , dp[i][2] 中最大值所对应的{0 , 1 , 2} 

dp[i][j]  =  max{ dp[i-1][k] * yetd[k][j] * table[j][leave[i]] }  k = 0 , 1 , 2 

因为我们只知道第i天的leave值。 所以dp[i][j] 实际上表示的第i天,天气为j的最大概率 是不准确的, 

说的准确点应该是 一个估价函数值 。

当第i天的天气确定,便知道通过转移过来的第i-1天的天气k。

const int maxn = 58 ;double  dp[maxn][3] ;double  table[3][4] = {{0.6 , 0.2 , 0.15 , 0.05} ,                       {0.25 , 0.3 , 0.2 , 0.25} ,                       {0.05 , 0.10 , 0.35 , 0.50}};double  yetd[3][3] = {{0.5 , 0.375 , 0.125 } ,                      {0.25 , 0.125 ,0.625} ,                      {0.25 , 0.375 , 0.375}} ;int   leave[maxn] ;int   father[maxn][3] ;int   ans[maxn] ;int   main(){      int t  , n  , i  , j , k  , T = 1  ;      char  str[8] ;      cin>>t  ;      while(t--){           cin>>n ;           for(i = 1 ; i <= n ; i++){               scanf("%s" , str) ;               if(strcmp(str , "Dry") == 0) leave[i] = 0 ;               else if(strcmp(str , "Dryish") == 0) leave[i] = 1 ;               else if(strcmp(str , "Damp") == 0) leave[i] = 2 ;               else leave[i] = 3 ;           }           dp[1][0] = 0.63 * table[0][leave[1]] ;           dp[1][1] = 0.17 * table[1][leave[1]] ;           dp[1][2] = 0.20 * table[2][leave[1]] ;           for(i = 2 ; i <= n ; i++){               for(j = 0 ; j < 3 ; j++){                    dp[i][j] = -1.0 ;                    for(k = 0 ; k < 3 ; k++){                        double w  =  dp[i-1][k] * yetd[k][j] * table[j][leave[i]] ;                        if(w > dp[i][j]){                              dp[i][j] = w ;                              father[i][j] = k ;                        }                    }               }           }           double mx = -1.0 ;           for(i = 0 ;  i < 3 ; i++){               if(dp[n][i] > mx){                    mx = dp[n][i] ;                    ans[n] = i ;               }           }           k = ans[n] ;           for(i = n-1 ; i >= 1 ; i--){               k = father[i+1][k] ;               ans[i] = k ;           }           printf("Case #%d:\n" , T++) ;           for(i = 1 ; i <= n ; i++){               if(ans[i] == 0) puts("Sunny") ;               else if(ans[i] == 1) puts("Cloudy") ;               else  puts("Rainy")  ;           }      }      return  0 ;}



hdu 4869  数学

 

题意:输入操作次数n和扑克牌数m,一开始扑克牌全都背面朝上。现在输入n个数xi,表示选择xi张牌翻转,问最后的牌的情况有多少种可能?

最后的答案就是ans=sigma C(m,k),k为所有能取到的1的个数。

最后1的个数的奇偶性,跟所有翻牌数的和的奇偶相同(每次翻牌,要么0->1,要么1->0,都是在改变1的个数奇偶)。

之后我们需要找到最少有mi个1,以及最大有mx个1;

费马小定理,假如p是质数,且gcd(a,p)=1,

那么 a^(p-1) ≡1(mod p)。

=>a^(p-2)=p^(-1)(mod p)

既有

(a/b) %M=a*(b^(M-2))%M 

typedef long long  LL ;const  LL  mod = 1000000009LL ;LL    Pow(LL x , LL y){      LL s = 1 ;      for(; y ; y >>= 1){          if(y & 1){ s *= x ; s %= mod ;}          x *= x ; x %= mod ;      }      return s ;}const  int  maxn = 100008 ;LL    c[maxn]  ;//c[i] = C(m , i)int   main(){      int x , i , j , L , R , mi , mx  , n , m ;      while(scanf("%d%d" , &n , &m) != EOF){           mi = mx = 0 ;           for(i = 1 ; i <= n ; i++){                scanf("%d" , &x) ;                if(mx + x <= m)  R = mx + x ;                else if(mi + x <= m){                     if((mi + x)%2 == m%2)  R = m ;                     else  R = m-1 ;                }                else  R = m - (x - (m - mi)) ;                if(mi - x >= 0)  L = mi - x ;                else if(mx - x >= 0){                     if(mi%2 == x%2) L = 0 ;                     else  L = 1 ;                }                else  L = x - mx ;                mi = L , mx = R ;           }           c[0] = 1LL ;           for(LL i = 1 ; i <= m ; i++){                if(m - i < i) c[i] = c[m-i] ;                else c[i] = c[i-1] * (LL)(m-i+1) % mod * Pow(i , mod-2) % mod ;           }           LL  sum = 0 ;           for(int i = mi ; i <= mx ; i += 2){                sum += c[i] ;                sum %= mod ;           }           cout<< sum << endl ;      }      return 0 ;}


hdu 4870  高斯消元

一个人注册两个账号,初始rating都是0,他每次拿低分的那个号去打比赛,赢了加50分,输了扣100分,胜率为p,他会打到直到一个号有1000分为止,问比赛场次的期望

+50  => +1 ;

-100 => -2 ;

思路:f(i, j)表示i >= j,第一个号i分,第二个号j分时候,达到目标的期望,那么可以列出转移为f(i, j) = p f(i', j') + (1 - p)f(i'' + j'') + 1
f(i', j')对应的是赢了加分的状态,f(i'', j'')对应输的扣分的状态,可以把50分当作一个单位,一共有20 * 21 / 2 = 210个状态,也就是对应了210个方程组,利用高斯消元去求解方程组,解出f(0, 0)就是答案

dp[i][j]   (i >=j )  

状态情况 

dp[0][0]                                                  1

dp[1][0] , dp[1][1] ,                                 2

.....

dp[19][0] , dp[19][1] ,  ,,,, dp[19][19]       20 

all  =  1 + 2 + 3 + ... + 20 =  (1 + 20) * 20 / 2 = 210 个。

做个hash映射,

dp[0][0]  = > x1

dp[1][0] = > x2  , dp[1][1] = > x3 ,

....

dp[19][19]  => x210  。

构造 方程组即可

a11 x1 + a12 x2 + ......a1n xn =  y1

a21 x1 + a22 x2 + ......a2n xn =  y2

.....

an1 x1 + an2 x2 + ......ann xn =  yn


//------begin of guass()-------------------/const   int   maxn = 220 ;const   double  eps = 1e-9 ;double  a[maxn][maxn] , x[maxn] ;  //a[i][j] 系数矩阵 , a[i][n+1]  = y[i] , x解int     n ;   //n个方程int     l[maxn] ; // 自由元void   guass(){       memset(l , 0 , sizeof(l)) ;       int r = 1 ,  res = 0 ;       for(int i = 1 ; i <= n ; i++){           for(int j = r ; j <= n ; j++){                if(fabs(a[j][i]) > eps){                     for(int k = i ; k <= n+1 ; k++)                         swap(a[j][k] , a[r][k]) ;                     break ;                }           }           if(fabs(a[r][i]) < eps){                 res++  ;                 continue ;           }           for(int j = 1 ; j <= n ; j++){                if(j != r && fabs(a[j][i]) > eps){                      double  temp = a[j][i] / a[r][i] ;                      for(int k = i ; k <= n+1 ; k++)                          a[j][k] -= temp * a[r][k] ;                }           }           l[i] = 1 ;           ++r ;       }       for(int i = 1 ; i <= n ; i++){           if(l[i]){              for(int j = 1 ; j <= n ; j++){                 if(fabs(a[j][i]) > 0)                      x[i] = a[j][n+1] / a[j][i] ;              }           }       }}//------end of guass()-------------------/int    lable[25][25] ;int    main(){       memset(lable , -1 , sizeof(lable)) ;       int i , j  ,  t = 0  , u , v  ;       for(i = 0 ; i < 20 ; i++){           for(j = 0 ; j <= i ; j++)  lable[i][j] = ++t ;       }       n =  210 ;       double  p  ;       while(cin>>p){             memset(a , 0  , sizeof(a)) ;             for(i = 0 ; i < 20 ; i++){                  for(j = 0 ; j < i ; j++){                        u = lable[i][j] ;                        a[u][u] = 1.0 ;                        a[u][n+1] = 1.0 ;                        v = lable[i][j+1] ;                        a[u][v] -= p ;                        v = lable[i][max(0 , j-2)] ;                        a[u][v] -= (1.0-p) ;                  }                  u = lable[i][i] ;                  a[u][u] = 1.0 ;                  a[u][n+1] = 1.0 ;                  v = lable[i+1][i] ;                  a[u][v] -= p ;                  v = lable[i][max(0 , i-2)] ;                  a[u][v] -= (1.0-p) ;             }             guass() ;             printf("%.6lf\n" , x[1]) ;       }       return  0 ;}


 






0 0
原创粉丝点击