Why so serious? --[NKU]schindlerlee

#

2010年1月12日星期二.sgu223 状态压缩动态规划

2010年1月12日星期二.sgu223
 状态压缩动态规划

sgu223:n*n的棋盘上放置k个王的放置方法。
基本方法和pku1185中的递推方法是一样的。
都是先求出一行中的所有合法状态,然后进行按行递推,
在递推的过程中判断两行之间是否有冲突。

#define L(n) (n << 1)
#define R(n) (n >> 1)
#define bin(n) (1 << n)
#define low(n) (n & (-n))
//http://www.cppblog.com/schindlerlee/
const int N = 10;
int n,sum,full;
int s[bin(N)],c[bin(N)],top;

LL f[N
+3][bin(N)][N*N];
//行 最后一行状态 已用的王的个数

bool judgeRow(int t)
{
  
int stat = t,cnt = 0;
  
int tp = 0,b = 0;
  
while(t > 0) {
      
if(b & t) {
          
return false;
      }
      b 
= t & 1,t >>= 1;
      
if(b == 1) cnt ++;
  }
  
if(sum < cnt)
    
return false;

  s[top] 
= stat,c[top] = cnt,top++;
  
return true;
}

bool contradict(int up,int down)
return ((up & down) || (L(up) & down) || (R(up) & down)); }

int main()
{
  
int i,j,k;
  scanf(
"%d%d",&n,&sum);
  full 
= bin(n) - 1;
  memset(f,
0,sizeof(f));
  
for(i = 0;i <= full;i++) {
      judgeRow(i);
  }

  f[
0][0][0= 1;
  
for(i = 1;i <= n;i++) {
      
for(j = 0;j < top;j++) {
          
int s1 = s[j],c1 = c[j]; //current

          
for(k = 0;k < top;k++) {
              
for(int c2 = 0;c2 <= sum;c2++) {
                  
int s2 = s[k];
                  
if(!f[i-1][s2][c2] ||c1 + c2 > sum) continue;
                  
//状态不可达或者使用王的数量超过k
    
                  
if(!contradict(s1,s2)) { //状态不冲突
                      f[i][s1][c1+c2] += f[i-1][s2][c2];
                  }
              }
          }
      }
  }
  LL res 
= 0;
  
for(i = 0;i <= full;i++) {
      res 
+= f[n][i][sum];
  }
  cout 
<< res << endl;

  
return 0;
}


 

posted @ 2010-01-13 22:39 schindlerlee 阅读(1124) | 评论 (0)编辑 收藏

2010年1月12日星期二.sgu222 组合数学知识

2010年1月12日星期二.sgu222

sgu222:n*n棋盘上放置k个车的不同放法
组合数学知识
C(n,k)选k行,然后A(n,k)求n列中k列的全排列
res = C(n,k) * A(n,k) 注意使用long long 型

LL res = 1;
for(i = 2;i <= n;i++) {
    res *= i;
}
for(i = 2;i <= n-k;i++) {
    res /= i;
}
res *= res;
for(i = 2;i <= k;i++) {
    res /= i;
}
cout << res << endl;


posted @ 2010-01-13 22:31 schindlerlee 阅读(1021) | 评论 (0)编辑 收藏

2010年1月13日星期三.pku1185 状态压缩动态规划

2010年1月13日星期三.pku1185
状态压缩动态规划

pku1185:题目是中文的,而且题目很经典,题意不再赘述。

这个题目比pku2411和sgu131两题来说多了一行状态需要储存
因为如果上上行和此行有关
而且此题不再是求完美覆盖的方式,而是求能最大的放置个数。

方法是先求出一行中的所有放置方法。
然后逐行递推,然后在递推的过程中枚举当前行状态,如果和上两行不冲突的话,就
进行放置个数的更新

f[N][60][60] //N行,上一行的状态号,上上行的状态号

具体看代码吧
  1 
  2 /*
  3  * SOUR:pku1185
  4  * ALGO:State Compression DP
  5  * DATE: 2010年 01月 13日 星期三 13:57:49 CST
  6  * COMM:4 http://www.cppblog.com/schindlerlee
  7  * */
  8 #include<iostream>
  9 #include<cstdio>
 10 #include<cstdlib>
 11 #include<cstring>
 12 #include<algorithm>
 13 using namespace std;
 14 typedef long long LL;
 15 const int maxint = 0x7fffffff;
 16 const long long max64 = 0x7fffffffffffffffll;
 17 
 18 #define bin(i) (1 << (i))
 19 #define low(i) ((i) & -(i))
 20 #define SL(i) ((i) << 1)
 21 #define SR(i) ((i) >> 1)
 22 
 23 void ckmax(int &a, int b)
 24 if (a < b) a = b; }
 25 
 26 const int N = 102;
 27 const int M = 10;
 28 
 29 //60是对M==10的一行进行深搜得到的最大状态数量
 30 int f[N][60][60], n, m, terrain[N], full;
 31 int s[60], top, c[60];
 32 
 33 int legal(int x)
 34 {
 35     int b = 0, cnt = 0, c;
 36     while (x > 0) {
 37         cnt++;
 38         c = low(x);
 39         if (SL(b) & x || SL(SL(b)) & x) {
 40             return -1;
 41         }
 42         x ^= c;
 43         b = c;
 44     }
 45     return cnt;
 46 }
 47 
 48 void preprocess()
 49 {
 50     int i, j, cnt;
 51     for (i = 0; i <= full; i++) {
 52         if ((cnt = legal(i)) >= 0) {
 53             s[top] = i, c[top] = cnt, top++;
 54         }
 55     }
 56 }
 57 
 58 bool contradict(int cur, int s1, int s2)
 59 return (cur & s1) || (cur & s2); }
 60 
 61 int main()
 62 {
 63     int i, j, k;
 64     char str[12];
 65     while (scanf("%d%d\n"&n, &m) == 2) {
 66         full = bin(m) - 1;
 67         preprocess();
 68 
 69         for (i = 1; i <= n; i++) {
 70             scanf("%s\n", str);
 71             int tmp = 0;
 72             for (j = 0; j < m; j++) {
 73                 tmp <<= 1;
 74                 if (str[j] == 'H') {
 75                     tmp |= 1;
 76                 }
 77             }
 78             terrain[i] = tmp;
 79         }
 80 
 81         for (i = 1; i <= n; i++) {
 82             for (j = 0; j < top; j++) { //枚举当前行
 83                 int cur = s[j], curcnt = c[j];
 84                 if (cur & terrain[i]) {
 85                     continue;
 86                 }    //不符合第i行地形要求
 87 
 88                 for (int k1 = 0; k1 < top; k1++) { //枚举前两行
 89                     for (int k2 = 0; k2 < top; k2++) {
 90                         if (!contradict(cur, s[k1], s[k2])) { //和上两行状态不冲突
 91                             ckmax(f[i][j][k1], f[i - 1][k1][k2] + curcnt);
 92                         }
 93                     }
 94                 }
 95             }
 96         }
 97 
 98         int res = 0;
 99         for (i = 0; i < top; i++) {
100             for (j = 0; j < top; j++) {
101                 ckmax(res, f[n][i][j]);
102             }
103         }
104         printf("%d\n", res);
105     }
106     return 0;
107 }
108 
109 


posted @ 2010-01-13 22:25 schindlerlee 阅读(1045) | 评论 (0)编辑 收藏

2010年1月11日星期一.sgu131 pku2411 状态压缩动态规划

2010年1月11日星期一.sgu131 pku2411
状态压缩动态规划。

pku2411:
给一个m*n(m,n<=11)的棋盘,用1*2和2*1的矩形覆盖这个棋盘,问有多少中方法对这个棋盘进行
完全覆盖。

这题有组合数学上的公式,但是只能对棋盘上没有障碍的情况有用,如果遇到有障碍的情况,只能
利用容斥原理进行计算,但是进行容斥原理的会非常复杂。

其实一看到数据范围就应该想到使用位运算的状态压缩动态规划。

主要的程序是
a表示要铺满的这一行的状态,b表示的是铺满上一行的状态a产生的下一行状态。
然后使用状态b继续递推。
 1 
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 using namespace std;
 8 typedef long long LL;
 9 const int maxint = 0x7fffffff;
10 const long long max64 = 0x7fffffffffffffffll;
11 #define bin(i) (1 << i)  /*1左移i位*/
12 #define emp(a,i) (!(a & bin(i))) /*判断a的i位是否位0*/
13 
14 const int N = 1 << 11;
15 LL f[N], g[N];
16 int m, n;
17 int full;
18 
19 void dfs(int a, int b, LL k)
20 {
21     if (a == full) {  //将a铺满之后形成的所有下一行状态b的铺法都有k种
22         g[b] += k; //产生b的所有状态求和
23         return;
24     }
25     for (int i = 0; i < m; i++) {
26         if (emp(a, i)) {
27             if (i < m - 1 && emp(a, i + 1)) {
28                 dfs(a | bin(i) | bin(i + 1), b, k);  //横铺
29             }
30             if (emp(b, i)) {
31                 dfs(a | bin(i), b | bin(i), k);  //竖铺
32             }
33             break;
34         }
35     }
36 }
37 
38 int main()
39 {
40   int i, j, k;
41   while(scanf("%d%d"&m, &n) == 2 && m && n) {
42       memset(f,0,sizeof(f));
43       memset(g,0,sizeof(g));
44       full = (1 << m) - 1;
45       f[full] = 1;
46       for (k = 0; k <= n; k++) {
47           for (i = 0; i <= full; i++) {
48               if (f[i]) { //如果此行的状态i可达
49                   dfs(i, 0, f[i]);
50               }
51           }
52           for (i = 0; i <= full; i++) {
53               f[i] = g[i];
54               g[i] = 0;
55           }
56       }
57       cout << f[0<< endl;
58   }
59   return 0;
60 }
61 

sgu131:pku2411的加强版
多了L型的瓷砖。这个最好是自己考虑一下,其实就是比上边的代码多了几行

const int N = 512;
LL f[N], g[N];
int m, n;
int full;

void dfs(int a, int b, LL k)
{
    
if (a == full) {  //将a铺满之后形成的所有下一行状态b的铺法都有k种
        g[b] += k;
        
return;
    }
    
for (int i = 0; i < m; i++) {
        
/* 六种铺法,按以下顺序分别是
a:##  ##  ##  #  #    #
b:    #    #  #  ##  ##
         * 
*/
        
if (emp(a, i)) {
            
if (i < m - 1 && emp(a, i + 1)) {
                dfs(a 
| bin(i) | bin(i + 1), b, k);
                
if (emp(b, i))
                  dfs(a 
| bin(i) | bin(i + 1), b | bin(i), k);
                
if (emp(b, i + 1))
                  dfs(a 
| bin(i) | bin(i + 1), b | bin(i + 1), k);
            }
            
if (emp(b, i)) {
                dfs(a 
| bin(i), b | bin(i), k);
                
if (i > 0 && emp(b, i - 1))
                  dfs(a 
| bin(i), b | bin(i) | bin(i - 1), k);
                
if (i < m - 1 && emp(b, i + 1))
                  dfs(a 
| bin(i), b | bin(i) | bin(i + 1), k);
            }
            
break;
        }
    }
}



posted @ 2010-01-13 22:11 schindlerlee 阅读(1168) | 评论 (0)编辑 收藏

2010年1月9日星期六.sgu125

2010年1月9日星期六.sgu125
sgu125:搜

题意还是很好理解的,给出一个N*N的矩阵,B[i][j]表示周围有多少个元素比他大,每个元素的取值范围是1-9,最大的复杂度是9^9次方,大约需要5s才能跑出来,肯定需要优化。

由于题目中的限制很多,非常容易想到判断当前B的合法性来判断。
仔细想想,加上一个或者两个剪枝就可以了。

贴个超级丑陋的代码。。。。 这个题的代码写的确实不太好
  1 /* 
  2  * SOUR:sgu125
  3  * ALGO:dfs
  4  * DATE: 2010年 01月 08日 星期五 22:46:13 CST
  5  * COMM:3 http://www.cppblog.com/schindlerlee/
  6  * */
  7 #include<iostream>
  8 #include<cstdio>
  9 #include<cstdlib>
 10 #include<cstring>
 11 #include<algorithm>
 12 using namespace std;
 13 typedef long long LL;
 14 const int maxint = 0x7fffffff;
 15 const long long max64 = 0x7fffffffffffffffll;
 16 const int N = 8;
 17 int A[N][N];
 18 int B[N][N],n;
 19 int S[N][N];
 20 
 21 #define PUSH(x,y) (S[x][y]++)
 22 #define POP(x,y) (S[x][y]--)
 23 #define legal(x,y) (S[x][y] <= B[x][y])
 24 
 25 bool dfs(int x, int y)
 26 {
 27   if (y == n + 1) {
 28       x++, y = 1;
 29   }
 30 
 31   if (x == n + 1) {
 32       for(int i = 1;i <= n;i++) {
 33           for(int j = 1;j <= n;j++) {
 34               if(S[i][j] != B[i][j]) return false;
 35           }
 36       }
 37       return true;
 38   }
 39   if(x == 3 && y == 1) {
 40       if(S[1][1!= B[1][1||
 41          S[1][2!= B[1][2||
 42          S[1][3!= B[1][3])
 43         return false;
 44   }
 45 
 46   for (int i = 1; i <= 9; i++) {
 47       A[x][y] = i;
 48       if (x > 1 && A[x][y] > A[x - 1][y]) {
 49           PUSH(x - 1, y);
 50           if (y > 1 && A[x][y] > A[x][y - 1]) {
 51               PUSH(x, y - 1);
 52               if(legal(x-1,y) && legal(x,y-1&& dfs(x,y+1)) return true;
 53               else {
 54                   POP(x-1,y);
 55                   POP(x,y-1);
 56               }
 57           } else if (y > 1 && A[x][y] < A[x][y - 1]) {
 58               PUSH(x, y);
 59               if(legal(x-1,y) && legal(x,y) && dfs(x,y+1)) return true;
 60               else {
 61                   POP(x-1,y);
 62                   POP(x,y);
 63               }
 64           } else {
 65               if(legal(x-1,y) && dfs(x,y+1)) return true;
 66               else {
 67                   POP(x-1,y);
 68               }
 69           }
 70       } else if (x > 1 && A[x][y] < A[x - 1][y]) {
 71           PUSH(x, y);
 72           if (y > 1 && A[x][y] > A[x][y - 1]) {
 73               PUSH(x, y - 1);
 74               if(legal(x,y) && legal(x,y-1&& dfs(x,y+1)) return true;
 75               else {
 76                   POP(x,y);
 77                   POP(x,y-1);
 78               }
 79           } else if (y > 1 && A[x][y] < A[x][y - 1]) {
 80               PUSH(x, y);
 81               if(legal(x,y) && dfs(x,y+1)) return true;
 82               else {
 83                   POP(x,y);
 84                   POP(x,y);
 85               }
 86           } else {
 87               if(dfs(x,y+1)) return true;
 88               else {
 89                   POP(x,y);
 90               }
 91           }
 92       }else {
 93           if (y > 1 && A[x][y] > A[x][y - 1]) {
 94               PUSH(x, y - 1);
 95               if(dfs(x,y+1)) return true;
 96               else {
 97                   POP(x,y-1);
 98               }
 99           } else if (y > 1 && A[x][y] < A[x][y - 1]) {
100               PUSH(x, y);
101               if(dfs(x,y+1)) return true;
102               else {
103                   POP(x,y);
104               }
105           } else {
106               if(dfs(x,y+1)) return true;
107               else {
108               }
109           }
110       }
111   }
112   return false;
113 }
114 
115 int main()
116 {
117   int i, j, k;
118   scanf("%d"&n);
119   for (i = 1; i <= n; i++) {
120       for (j = 1; j <= n; j++) {
121           scanf("%d"&B[i][j]);
122       }
123   }
124 
125   if (dfs(11)) {
126       for(int i = 1;i <= n;i++) {
127           for(int j = 1;j <= n;j++) {
128               printf("%d ",A[i][j]);
129           }
130           putchar(10);
131       }
132   }else {
133       puts("NO SOLUTION");
134   }
135   return 0;
136 }
137 

posted @ 2010-01-09 01:57 schindlerlee 阅读(1285) | 评论 (0)编辑 收藏

2010年1月7日星期四.sgu170

2010年1月7日星期四.sgu170
sgu170:
简单题。
题意很简单,就是求两个只有+-组成的字符串,通过互换相邻的两个+-,是否能够由第一个串,变成第二个,给出最短的变换步数。


直觉的想法:广搜
    这样显然有问题,字符串长5000,怎么搜复杂度都太高。

猜想:贪心
对于两个字符串a,b,相同的两个区间,如果a[s....t] 和
b[s...t]所含的+-数量一样多,那么由a[s...t] 到 b[s...t]
的最小距离一定是其中减号或者加号的差的绝对值的和

比如:
-+-+-

---++
最小步数就是0 + 1 + 2 = 3

本题就直接求两个串的符号差即可
 1 http://www.cppblog.com/schindlerlee
 2 bool judge()
 3 {
 4   len1 = strlen(stra);
 5   len2 = strlen(strb);
 6   if(len1 != len2) return false;
 7   int i,res = 0;
 8   for(i = 0;i < len1;i++) {
 9       if(stra[i] == '-') { out1[top1++= i; }
10       if(strb[i] == '-') { out2[top2++= i; }
11   }
12   if(top1 != top2) return false;
13   for(i = 0;i < top1;i++) {
14       res += abs(out1[i] - out2[i]);
15   }
16   printf("%d\n",res);
17   return true;
18 }
19 
20 


posted @ 2010-01-07 20:04 schindlerlee 阅读(1060) | 评论 (2)编辑 收藏

2010年1月3日星期日:sgu168:猥琐输入输出的应用 + 简单dp

sgu168:猥琐输入输出的应用 + 简单dp
用getchar和putchar进行输入输出,会比scanf和printf快很多很多。

输入
 1 
 2 char t;
 3 scanf("%d%d\n"&m, &n);
 4 memset(B, 1sizeof(B));
 5 for(i = 1; i <= m; i++)  {
 6     for(j = 1; j <= n; j++) {
 7         minus = 1;
 8         tmp = 0;
 9         t = getchar();
10         while(t == ' ') t = getchar();
11         if(t == '-') {
12             t = getchar();
13             minus = -1;
14         }
15         while(t != ' ' && t != 10) {
16             tmp = tmp * 10 + t - '0';
17             t = getchar();
18         }
19         A[i][j] = tmp * minus;
20         //scanf("%d", &A[i][j]);
21     }
22     while(t != 10) {t = getchar();}
23 }

输出
 1 
 2 void print(int t)
 3 {
 4     if(t > -10 && t < 10) {
 5         printf("%d",t);
 6         return;
 7     }
 8     if(t < 0) {
 9         putchar('-');
10         t = -t;
11     }
12     top = 0;
13     while(t > 0) {
14         out[top++= t % 10;
15         t /= 10;
16     }
17     for(int i = top - 1;i >= 0;i--) {
18         putchar('0' + out[i]);
19     }
20 }

我sb了好久。。。。没发现还有负数

dp过程

for(int i = n; i >= 1; i--)
    
for(int j = m; j >= 1; j--)
        B[j][i] 
= min(min(A[j][i], B[j][i + 1]), min(B[j + 1][i], B[j - 1][i + 1])); 


977046    03.01.10 15:41    schindlerlee     168    .CPP    Accepted    958 ms    8183 kb


posted @ 2010-01-03 20:49 schindlerlee 阅读(1334) | 评论 (0)编辑 收藏

2009年12月26日星期六.pku2165 计算几何

2009年12月26日星期六.pku2165
计算几何
算法:将窗口投影到yz平面和xz平面,分别计算

上图是投影到yz平面的情况,可以算出斜率的交区间,如果不存在则无解,然后随便从中选出一个斜率。
然后算出和第一个窗口的Y交点


上图是投影到xz平面的情况,需要两两算出直线在x轴上的投影区间,然后随便选一个点作为出始点ansx。


然后由这个点开始,算出斜率的交区间,进而求出和第一条窗的x交点

有了这两个点,就可以利用比例,求出和其他所有窗的交点了
最后,很恶心的是精度,需要特别注意判断无解的情况,一定要用
int dcmp ( double x) { return (x > eps) - (x < -eps);}
我在精度上卡了好几次,最后double eps = 1e-10; 时过的
  1 /* 
  2  * SOUR:pku2165
  3  * ALGO:computational geometry
  4  * DATE: 2009年 12月 26日 星期六 21:31:06 CST
  5  * COMM:4
  6  * */
  7 #include<iostream>
  8 #include<cstdio>
  9 #include<cstdlib>
 10 #include<cstring>
 11 #include<algorithm>
 12 #include<cassert>
 13 #include<cmath>
 14 using namespace std;
 15 typedef long long LL;
 16 const int maxint = 0x7fffffff;
 17 const long long max64 = 0x7fffffffffffffffll;
 18 const int N = 128;
 19 int n;
 20 double h,ansx,offset;
 21 struct W {
 22     double x1,y1;
 23     double x2,y2,z;
 24 }w[N];
 25 
 26 double eps = 1e-10;
 27 int dcmp(double x) { return (x > eps) - (x < -eps);}
 28 
 29 const double inf = 1e30;
 30 
 31 void ckmax(double &a,double b) { if(dcmp(a - b) < 0) a = b; }
 32 void ckmin(double &a,double b) { if(dcmp(a - b) > 0) a = b; }
 33 
 34 bool CalcY()
 35 {
 36     int i;
 37     double up  = inf,down = -inf;
 38     for(i = 0;i < n;i++) {
 39         ckmax(down,w[i].y1 / w[i].z);
 40         ckmin(up,w[i].y2 / w[i].z);
 41     }
 42     if(dcmp(down - up) > 0) {
 43         return false;
 44     }
 45     double tmp = (up + down)/ 2;
 46     h = tmp * w[0].z;
 47     //printf("CalcY succeded h = %.6f\n",h);
 48     return true;
 49 }
 50 
 51 struct P
 52 {
 53     double x1,x2;
 54 }interval[N*N];
 55 int top;
 56 
 57 double dist(double a,double b) { return sqrt(a * a + b * b); }
 58 
 59 bool CalcX()
 60 {
 61     int i ,j;
 62     double z,x,len,L;
 63     top = 0;
 64     for(i = 0;i < n;i++) {
 65         for(j = i + 1;j < n;j++) {
 66             z = w[j].z - w[i].z;
 67             x = w[j].x2 - w[i].x1;
 68             len = dist(z,x);
 69             L = w[j].z * len / (w[j].z - w[i].z);
 70             x = x/len * L;
 71             interval[top].x1 = w[j].x2 - x;
 72 
 73             z = w[j].z - w[i].z;
 74             x = w[j].x1 - w[i].x2;
 75             len = dist(z,x);
 76             L = w[j].z * len / (w[j].z - w[i].z);
 77             x = x/len * L;
 78             interval[top].x2 = w[j].x1 - x;
 79 
 80             top ++;
 81         }
 82     }
 83     double left = -inf,right = inf;
 84     for(i = 0;i < top;i++) {
 85         //printf("[%d] x1= %.6f,x2 = %.6f\n",i,interval[i].x1,interval[i].x2);
 86         ckmax(left,interval[i].x1);
 87         ckmin(right,interval[i].x2);
 88     }
 89     //printf("left = %.6f,right = %.6f\n",left,right);
 90     if(dcmp(left - right) > 0
 91         return false;
 92     //if(left > right) 
 93         //return false;
 94 
 95     ansx = (left + right) /2;
 96     left = -inf,right = inf;
 97     for(i = 0;i < n;i++) {
 98         ckmax(left,(w[i].x1 - ansx) / w[i].z);
 99         ckmin(right,(w[i].x2 - ansx) / w[i].z);
100     }
101     //assert(left < right);
102     double mid = (left + right)/2;
103     offset = mid * w[0].z;
104     return true;
105 }
106 
107 
108 int main()
109 {
110     int i,j,k;
111     scanf("%d",&n);
112     for(i = 0;i < n;i++) {
113         scanf("%lf%lf",&w[i].x1,&w[i].y1);
114         scanf("%lf%lf%lf",&w[i].x2,&w[i].y2,&w[i].z);
115     }
116     if(!CalcY()) {
117         printf("UNSOLVABLE\n");
118         return 0;
119     }
120     if(!CalcX()) {
121         printf("UNSOLVABLE\n");
122         return 0;
123     }
124 
125     printf("SOLUTION\n");
126     printf("%.6f\n",ansx);
127     for(i = 0;i < n;i++) {
128         double x = w[i].z * offset / w[0].z + ansx;
129         double y = w[i].z * h      / w[0].z;
130         double z = w[i].z;
131         printf("%.6f %.6f %.6f\n",x,y,z);
132     }
133     return 0;
134 }
135 
136 


posted @ 2009-12-27 00:30 schindlerlee 阅读(1008) | 评论 (0)编辑 收藏

2009年12月26日星期六.sgu122 符合Ore条件的哈密顿路 搜索方法

2009年12月26日星期六.sgu122
半个月了。。。才看出错来。。

构造法很复杂不会,说说搜索的思路:搜索时按每个点临接点的度数从小到大来搜就可以了

此题非常阴险:
1.scanf读入会超时....
2.vector存邻接表一定超时,邻接矩阵又没办法按照度数排序,再开一个矩阵会超内存,第68,69两行只能选一个用,不然会越界
3.每行存的是临接的点,但是没有32~36行会WA @ test 24!!!!!!
4.No Solution是不存在的
 1 /* 
 2  * SOUR:sgu122
 3  * ALGO:graph theory
 4  * DATE: 2009年 12月 04日 星期五 20:33:43 CST
 5  * COMM:5
 6  * Ore条件: 对于一个简单图满足任意两个顶点的度数和都大于等于n则必定存在哈密顿回路
 7  * * */
 8 #include<iostream>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<cstring>
12 #include<algorithm>
13 #include<cassert>
14 #include<vector>
15 using namespace std;
16 const int N = 1001;
17 int cnt[N],deg[N],n,vis[N],out[N],top;
18 int g[N][N];
19 const int M = 6100;
20 char s[M];
21 
22 bool cmp(int a,int b) { return deg[a] < deg[b]; } 
23 bool dfs(int u,int left)
24 {
25     if(left == 0) {
26         for(int i = 0;i < cnt[u];i++) {
27             if(g[u][i] == 1) {
28                 return true;
29             }
30         }
31         //我不知道题目为什么会这么阴险!!
32         for(int i = 0;i < cnt[1];i++) {
33             if(g[1][i] == u) {
34                 return true;
35             }
36         }
37         return false;
38     }
39     for(int i = 0;i < cnt[u];i++) {
40         int v = g[u][i];
41         if(!vis[v]) {
42             vis[v] = 1;
43             if(dfs(v,left - 1)) {
44                 out[top++= v;
45                 return true;
46             }
47             vis[v] = 0;
48         } 
49     }
50     return false;
51 }
52 
53 int main() 
54 {
55     int i,j,k,tmp,len;
56     scanf("%d\n",&n);
57     for(i = 1;i <= n;i++) {
58         fgets(s,M,stdin);
59         s[(len = strlen(s)) -1= ' ';
60 
61         for(j = 0;j < len;) {
62             k = 0;
63             while(s[j] >= '0') {
64                 k = k * 10 + s[j] - '0';
65                 j++;
66             }
67             while(s[j] == ' ') {j++;}
68             g[i][cnt[i]++= k;
69             //g[k][cnt[k]++] = i;
70             deg[k]++;
71             deg[i]++;
72         }
73     }
74     for(i = 1;i <= n;i++) {
75         sort(&g[i][0],&g[i][cnt[i]],cmp);
76     }
77 
78     vis[1= true;
79     dfs(1,n-1);
80     printf("1");
81     for(i = 0;i < top;i++) {
82         printf(" %d",out[i]);
83     }
84     printf(" 1\n");
85 
86     return 0;
87 }
88 

posted @ 2009-12-26 16:56 schindlerlee 阅读(1219) | 评论 (0)编辑 收藏

2009年12月25日星期五.sgu139 八数码问题的推广 15数码..........

 1 /*
 2  * SOUR:sgu139
 3  * ALGO:8数码问题的推广
 4  * DATE: 2009年 12月 25日 星期五 21:37:54 CST
 5  * COMM:4http://www.cppblog.com/schindlerlee
 6  * */
 7 #include<iostream>
 8 #include<cstdio>
 9 #include<cstdlib>
10 #include<cstring>
11 #include<algorithm>
12 using namespace std;
13 typedef long long LL;
14 const int maxint = 0x7fffffff;
15 const long long max64 = 0x7fffffffffffffffll;
16 
17 const int N = 16;
18 int num[N];
19 int main()
20 {
21     //最终状态  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0
22     //逆序数15
23     int i,j,offset = 0;
24     int inver = 0;
25     for(i = 0;i < N;i++) {
26         scanf("%d",num + i);
27         if(num[i] == 0) {
28             offset += 3 - (i / 4);
29             offset += 3 - (i % 4);
30         }
31     }
32     for(i = 1;i < N;i++) {
33         for(j = i - 1;j >= 0;j--) {
34             if(num[j] > num[i]) {
35                 inver ++;
36             }
37         }
38     }
39     //维度为偶数的这种问题,会改变会改变数列的逆序奇偶性,所以还要判断哈密顿距离的奇偶
40     //维度为奇数的这种问题,则只需要判断逆序的奇偶性
41     //奇偶性相同且offset为偶 或
42     //奇偶性不同且offset为奇 这样的状态都能互相到达
43     if((inver % 2 == 1== (offset % 2 == 0)) {
44         puts("YES");
45     }else {
46         puts("NO");
47     }
48     return 0;
49 }
50 
51 
52 

posted @ 2009-12-25 21:59 schindlerlee 阅读(1138) | 评论 (0)编辑 收藏

2009年12月25日星期五.sgu179

2009年12月25日星期五.sgu179
找一个合法的括号序列的下一个合法next_permutation
我打了个表,标*的为正确的排列。
我们发现在()()()()之后的都是非法序列,合法序列只占开始的一小部分。
然后我就用next_permutation水了一下,就过了
WindyWinter还介绍了一个找规律的方法: http://www.briefdream.com/sgu-179/
http://www.cppblog.com/schindlerlee/

/*
00001111 (((()))) *
00010111 ((()())) *
00011011 ((())()) *
00011101 ((()))() *
00011110 ((())))(
00100111 (()(())) *
00101011 (()()()) *
00101101 (()())() *
00101110 (()()))(
00110011 (())(()) *
00110101 (())()() *
00110110 (())())(
00111001 (()))(()
00111010 (()))()(
00111100 (())))((
01000111 ()((())) *
01001011 ()(()()) *
01001101 ()(())() *
01001110 ()(()))(
01010011 ()()(()) *
01010101 ()()()() *
01010110 ()()())(
01011001 ()())(()
01011010 ()())()(
01011100 ()()))((
01100011 ())((())
01100101 ())(()()
01100110 ())(())(
01101001 ())()(()
01101010 ())()()(
01101100 ())())((
01110001 ()))((()
01110010 ()))(()(
01110100 ()))()((
01111000 ())))(((
10000111 )(((()))
10001011 )((()())
10001101 )((())()
10001110 )((()))(
10010011 )(()(())
10010101 )(()()()
10010110 )(()())(
10011001 )(())(()
10011010 )(())()(
10011100 )(()))((
10100011 )()((())
10100101 )()(()()
10100110 )()(())(
10101001 )()()(()
10101010 )()()()(
10101100 )()())((
10110001 )())((()
10110010 )())(()(
10110100 )())()((
10111000 )()))(((
11000011 ))(((())
11000101 ))((()()
11000110 ))((())(
11001001 ))(()(()
11001010 ))(()()(
11001100 ))(())((
11010001 ))()((()
11010010 ))()(()(
11010100 ))()()((
11011000 ))())(((
11100001 )))(((()
11100010 )))((()(
11100100 )))(()((
11101000 )))()(((
11110000 ))))((((
*/
 1 /*
 2  * SOUR:sgu179
 3  * ALGO:math
 4  * DATE: 2009年 12月 25日 星期五 16:22:44 CST
 5  * COMM:3 http://www.cppblog.com/schindlerlee/
 6  * */
 7 #include<iostream>
 8 #include<cstdio>
 9 #include<cstdlib>
10 #include<cstring>
11 #include<algorithm>
12 using namespace std;
13 typedef long long LL;
14 const int maxint = 0x7fffffff;
15 const long long max64 = 0x7fffffffffffffffll;
16 
17 const int N = 10010;
18 char s[N], last[N];
19 int len;
20 
21 int judge()
22     //1 right 0 false -1 exceed
23 {
24     int i;
25     for(i = 0;i < len ;i++) {
26         if(last[i] > s[i]) {
27             break;
28         }else if(last[i] < s[i]) {
29             return -1;
30         }
31     }
32     int top = 0;
33     for(int i = 0;i < len;i++) {
34         if(s[i] == '(') {
35             top ++;
36         }else {
37             if(top > 0)
38                 top --;
39             else {
40                 return 0;
41             }
42         }
43     }
44     return (top == 0);
45 }
46 
47 int main()
48 {
49     int i,j,k;
50     scanf("%s",s);
51     len = strlen(s);
52     for(i = 0;i < len;i++) {
53         if(i & 1) {
54             last[i] = ')';
55         }else {
56             last[i] = '(';
57         }
58     }
59 
60     next_permutation(s,s + len);
61     while(1) {
62         int r = judge();
63         if(r == 0) {
64             next_permutation(s,s + len);
65         }else if(r == 1) {
66             for(i = 0;i < len;i++) {
67                 putchar(s[i]);
68             }
69             putchar(10);
70             break;
71         }else {
72             printf("No solution\n");
73             break;
74         }
75     }
76     return 0;
77 }
78 
79 
80 


posted @ 2009-12-25 17:15 schindlerlee 阅读(970) | 评论 (0)编辑 收藏

2009年12月21日星期一.sgu499

2009年12月21日星期一.sgu499
注:此文包括线性筛法,质因子分解,dfs生成一个数的所有因子

sgu499:我想撞墙
http://www.cppblog.com/schindlerlee/
那天arxor看我和angelclover在做,然后也在看题,这个题我还没看,然后arxor大牛就给我说了个想法

把每个数分解素因子,然后dfs出这个数的所有因子。
对每个数进行一次此操作,最后找最大的且被访问了两边以上的因子,
但是这个方法tle在test 20了。怪我当时没细想,被大牛随便一说就觉得这个方法很好。。。。然后。。。杯具了

上代码:tle@20
 1 /*
 2  * SOUR:sgu Greatest Greatest Common Divisor
 3  * ALGO:因子分解
 4  * DATE: 2009年 12月 20日 星期日 19:24:49 CST
 5  * COMM:3http://www.cppblog.com/schindlerlee/
 6  * */
 7 #include<iostream>
 8 #include<cstdio>
 9 #include<cstdlib>
10 #include<cstring>
11 #include<algorithm>
12 using namespace std;
13 typedef long long LL;
14 const int maxint = 0x7fffffff;
15 const long long max64 = 0x7fffffffffffffffll;
16 
17 const int N = 1000010;
18 int vis[N], n, is_prime[N], primes[N], top;
19 int exp[100], num[100], cnt;
20 int can[N];
21 void generate()
22 {
23     int i, j, k;
24     top = 0;
25     fill(is_prime, is_prime + N, 1);
26     for (i = 2; i <= 1000000; i++) {
27         if (is_prime[i]) {
28             primes[top++= i;
29         }
30         for (j = 0; j < top && i * primes[j] <= 1000000; j++) {
31             is_prime[i * primes[j]] = 0;
32             if (i % primes[j] == 0)
33                 break;
34         }
35     }
36     //for(i = 0;i < top;i++) {
37     //printf("%d\n",primes[i]);
38     //}
39 }
40 
41 void factor(int x)
42 {
43     //printf("factor %d\n",x);
44     cnt = 0;
45     for (int i = 0; i < top && x > 1; i++) {
46         if (x % primes[i] == 0) {
47             //printf("primes[i] = %d\n",primes[i]);
48             can[i]++;
49             num[cnt] = primes[i];
50             exp[cnt] = 0;
51             while (x % primes[i] == 0) {
52                 exp[cnt]++;
53                 x /= primes[i];
54             }
55             cnt++;
56         }
57     }
58 }
59 
60 void dfs(int x, int level)
61 {
62     if (level == cnt) {
63         //printf("dfs x= %d\n",x);
64         vis[x]++;
65         return;
66     }
67     dfs(x, level + 1);
68     for (int i = 1; i <= exp[level]; i++) {
69         x *= num[level];
70         dfs(x, level + 1);
71     }
72 }
73 
74 int main()
75 {
76     int i, j, k;
77     generate();
78     scanf("%d"&n);
79     for (i = 0; i < n; i++) {
80         scanf("%d"&k);
81         factor(k);
82         dfs(10);
83     }
84     for (i = N - 1; i >= 0; i--) {
85         if (vis[i] >= 2) {
86             printf("%d\n", i);
87             break;
88         }
89     }
90     return 0;
91 }
92 

然后比赛完google了以下,原来是水题,不予解释了,贴代码
 1 
 2 const int N = 1000010;
 3 int vis[N],n,m;
 4 void chkmax(int &x,int k) { if(x < k) x = k; }
 5 int main()
 6 {
 7     int i,j,k;
 8     scanf("%d",&n);
 9     for(i = 0;i < n;i++) {
10         scanf("%d",&k);
11         vis[k] ++;
12         chkmax(m,k);
13     }
14 
15     int res = 1;
16     for(i = 2;i <= m;i++) {
17         int tmp = 0;
18         for(j = i;tmp < 2 && j <= m;j += i) {
19             tmp += vis[j];
20         }
21         if(tmp >= 2) res = i;
22     }
23     printf("%d\n",res);
24
25     return 0;
26 }
27 
28 

结果第二天arxor,说他用那个方法过了。。。。。。。。。
然后我看了他的代码,我发现原来我的因子分解是没有优化的。。。
然后把第45行改成
    for (int i = 0; primes[i] * primes[i] <= x && i < top && x > 1; i++) {

过了。。。。。

posted @ 2009-12-21 20:54 schindlerlee 阅读(1085) | 评论 (0)编辑 收藏

2009年12月13日星期日.sgu144 169

sgu 144:meeting

纯数学题,算概率
第一个人到达的时间做x轴,第二个人的到达时间做y轴
符合条件的概率是|x-y| <= z
如图所示,正方形和两条直线相交之间的阴影部分面积即是所求。


显然的,如果两个人的到达区间不相等,也只要求出矩形和直线相交的面积即可
 1 /* 
 2  * SOUR:sgu144
 3  * ALGO:概率
 4  * DATE: 2009年 12月 13日 星期日 22:14:36 CST
 5  * COMM:3 http://www.cppblog.com/schindlerlee/
 6  * 横坐标代表第一个人到达的时间,纵坐标代表第二个人到达的时间
 7  * |x-y| <= z
 8  * */
 9 #include<iostream>
10 #include<cstdio>
11 #include<cstdlib>
12 #include<cstring>
13 #include<algorithm>
14 using namespace std;
15 typedef long long LL;
16 const int maxint = 0x7fffffff;
17 const long long max64 = 0x7fffffffffffffffll;
18 
19 double sqr(double x) { return x * x;}
20 int main()
21 {
22     double x,y,z,ans;
23     scanf("%lf%lf%lf",&x,&y,&z);
24     x *= 60,y *= 60;
25     ans = 1 - sqr(y-x-z)/sqr(y - x);
26     printf("%.7f\n",ans);
27     return 0;
28 }
29 
30 

sgu:169 numbers 纯数学方法
不知道别人是怎么做的,我是纯的打表,找规律。
发现只有11111111....1x的形式才可以,于是就再打个表看看。
11 % = 0
12 % = 0
13 % = 1
14 % = 2
15 % = 0
16 % = 4
17 % = 3
18 % = 2
19 % = 1

111 % = 0
112 % = 0
113 % = 2
114 % = 2
115 % = 0
116 % = 2
117 % = 5
118 % = 6
119 % = 2

1111 % = 0
1112 % = 0
1113 % = 0
1114 % = 2
1115 % = 0
1116 % = 0
1117 % = 4
1118 % = 6
1119 % = 3

11111 % = 0
11112 % = 0
11113 % = 1
11114 % = 2
11115 % = 0
11116 % = 4
11117 % = 1
11118 % = 6
11119 % = 4

111111 % = 0
111112 % = 0
111113 % = 2
111114 % = 2
111115 % = 0
111116 % = 2
111117 % = 6
111118 % = 6
111119 % = 5

1111111 % = 0
1111112 % = 0
1111113 % = 0
1111114 % = 2
1111115 % = 0
1111116 % = 0
1111117 % = 0
1111118 % = 6
1111119 % = 6

11111111 % = 0
11111112 % = 0
11111113 % = 1
11111114 % = 2
11111115 % = 0
11111116 % = 4
11111117 % = 3
11111118 % = 6
11111119 % = 7

111111111 % = 0
111111112 % = 0
111111113 % = 2
111111114 % = 2
111111115 % = 0
111111116 % = 2
111111117 % = 5
111111118 % = 6
111111119 % = 8

1111111111 % = 0
1111111112 % = 0
1111111113 % = 0
1111111114 % = 2
1111111115 % = 0
1111111116 % = 0
1111111117 % = 4
1111111118 % = 6
1111111119 % = 0

 1 /* 
 2  * SOUR:sgu169
 3  * ALGO:math
 4  * DATE: 2009年 11月 29日 星期日 11:11:37 CST http://www.cppblog.com/schindlerlee
 5  * COMM:2
 6  * */
 7 #include<iostream>
 8 #include<cstdio>
 9 #include<cstdlib>
10 #include<cstring>
11 #include<algorithm>
12 using namespace std;
13 typedef long long LL;
14 const int maxint = 0x7fffffff;
15 const long long max64 = 0x7fffffffffffffffll;
16 
17 int n;
18 int main()
19 {
20     int i,j,pre = 1;
21     scanf("%d",&n);
22     if(n == 1) {
23         printf("8\n");
24     }else {
25         int res = 1;
26         if((n-1% 3 == 0) res +=2;
27         if((n-1% 6 == 0) res ++;
28         printf("%d\n",res);
29     }
30 
31     return 0;
32 }
33 


posted @ 2009-12-20 00:41 schindlerlee 阅读(1115) | 评论 (0)编辑 收藏

Majority Problem:给出n个物品,判断是否有超过一半的物品是相同的。


给出n个物品,判断是否有超过一半的物品是相同的。
前提是,两个物品只有放到一个特殊的装置中才能判断是否相同。

Θ(n^2):brute force
    对每一个物体遍历
Θ(nlogn):分治,下面的代码纯属表达思想用,没有测试!!!
    int divide(int *a,int n)
    {
        if(n == 2) {
            if(a[0] == a[1]) {
                return a[0];
            }
            return EMPTY;
        }
        int ca = divide(a,n/2);
        int cb = divide(a + n/2.n - n/2);
        if(ca != EMPTY) {
            if(ca is majority in a[n/2 ... n-n/2]) {
                return ca;
            }
        }
        if(cb != EMPTY) {
            if(cb is majority in a[0...n/2]) {
                return cb;
            }
        }
        return EMPTY;
    }

Θ(n):规模下降
Lemma:如果两个物品不同那么在去掉这两个物品的剩余物品中,如果存在Majority
    元素,那么这个元素也是去掉之前的解.
设考虑要去掉的两个物品是A,B
    如果A,B都不是Majority元素,那么在去掉A,B之后Majority元素一定不变
    如果A是Majority元素,那么去掉两个元素之后,在n-2个物品中原来的Majority物品个数
        由n/2 + 1变为 n/2,依然在n-2个物品中占大多数

贴<<Algorithms Design Techniques and Analysis>>上的代码,哥亲自输入的,
我的技术博客http://www.cppblog.com/schindlerlee

Algorithm 5.9 MAJORITY
Input:An array A[1...n] of n elements.
Output:The majority element if it exists:otherwise non.

 1. c ← candidate(1)
 2. cout ← 0;
 3. for j ← 1 to n
 4.        if A[j] == c then count ← count + 1
 5. end for
 6. if count > ⌊n/2⌋ then return c
 7. else return none
 8.
 9. Procedure candidate(m)
10. j ← m;c ← A[m];count ← 1
11. while j < n and count > 0
12.     j ← j + 1
13.     if A[j] == c then count ← count + 1
14.     else count ← count - 1
15. end while
16. if j == n then return c
17. else return candidate(j + 1)        


posted @ 2009-12-18 18:04 schindlerlee 阅读(1083) | 评论 (0)编辑 收藏

2009年12月13日星期日.pku2353 最短路

最短路的变形,题意比较简单,具体看代码

  1 /* 
  2  * SOUR:pku 2353
  3  * ALGO:dp
  4  * DATE: 2009年 12月 12日 星期六 20:05:20 CST
  5  * COMM:3
  6  * */
  7 #include<iostream>
  8 #include<cstdio>
  9 #include<cstdlib>
 10 #include<cstring>
 11 #include<algorithm>
 12 #include<queue>
 13 using namespace std;
 14 typedef long long LL;
 15 const int maxint = 0x7fffffff;
 16 const long long max64 = 0x7fffffffffffffffll;
 17 const int N = 512;
 18 const int inf = 100000001;
 19 int m,n,x,y;
 20 int g[N][N],out[N*N],top,dis[N][N],vis[N][N],pre[N][N][2]; 
 21 
 22 struct Path
 23 {
 24     int x,y;
 25     int len;
 26     Path(){}
 27     Path(int a,int b,int c) { x = a,y = b,len = c;}
 28     friend bool operator < (Path a,Path b) {
 29         return a.len > b.len;
 30     }
 31 };
 32 
 33 int search()
 34 {
 35     int i,j,k;
 36     for(i = 1;i < m;i++) {
 37         for(j = 0;j < n;j++) {
 38             dis[i][j] = maxint;
 39         }
 40     }
 41     for(i = 0;i < n;i++) {
 42         dis[0][i] = g[0][i];
 43     }
 44     priority_queue<Path> que;
 45     for(i = 0;i < n;i++) {
 46         que.push(Path(0,i,g[0][i]));
 47     }
 48 
 49     int sum;
 50     int res = maxint;
 51     while(!que.empty()) {
 52         Path u = que.top(); que.pop();
 53         if(u.x == m - 1) {
 54             if(u.len < res) {
 55                 res = u.len;
 56                 x = u.x;
 57                 y = u.y;
 58                 continue;
 59             }
 60         }
 61         if(u.len != dis[u.x][u.y])
 62             continue;
 63 
 64         if (dis[u.x +1][u.y] > u.len + g[u.x+1][u.y]) {
 65             dis[u.x +1][u.y] = u.len + g[u.x+1][u.y];
 66             que.push(Path(u.x + 1,u.y,u.len + g[u.x+1][u.y]));
 67             pre[u.x+1][u.y][0= u.x;
 68             pre[u.x+1][u.y][1= u.y;
 69         }
 70 
 71         i = u.y - 1;
 72         if(i >= 0 && i < n) {
 73             sum = g[u.x][i];
 74             if (dis[u.x][i] > u.len + sum) {
 75                 dis[u.x][i] = u.len + sum;
 76                 que.push(Path(u.x,i,u.len + sum));
 77                 pre[u.x][i][0= u.x;
 78                 pre[u.x][i][1= u.y;
 79             }
 80         }
 81 
 82         i = u.y + 1;
 83         if(i >= 0 && i < n) {
 84             sum = g[u.x][i];
 85             if (dis[u.x][i] > u.len + sum) {
 86                 dis[u.x][i] = u.len + sum;
 87                 que.push(Path(u.x,i,u.len + sum));
 88                 pre[u.x][i][0= u.x;
 89                 pre[u.x][i][1= u.y;
 90             }
 91         }
 92     }
 93     return sum;
 94 }
 95 
 96 int main()
 97 {
 98     int i,j,k;
 99     scanf("%d%d",&m,&n);
100     for(i = 0;i < m;i++) {
101         for(j = 0;j < n;j++) {
102             scanf("%d",&g[i][j]);
103             pre[i][j][0= -1;
104             pre[i][j][1= -1;
105         }
106     }
107 
108     int res = search();
109     //printf("%d\n",res);
110     int tx,ty;
111     while(x != -1 && y != -1) {
112         out[top++= y;
113         tx = pre[x][y][0];
114         ty = pre[x][y][1];
115         x = tx,y = ty;
116     }
117     for(i = top - 1;i >= 0;i--) {
118         printf("%d\n",out[i] + 1);
119     }
120     return 0;
121 }
122 
123 


posted @ 2009-12-13 21:32 schindlerlee 阅读(1165) | 评论 (0)编辑 收藏

仅列出标题
共7页: 1 2 3 4 5 6 7