刚刚去山东理工大学的OJ看了一下问题没有公开。。。不过幸好大部分题可以再其他网站上找到 XD
四子棋 --ACM Mid-Central 1999 // 对抗搜索(要求剪枝, 容易超时) http://poj.org/problem?id=1568
这个题是我们比赛过程中尝试的最后一道题,但是写到一半就断电了.....(就算不断电我也没有信心能A过去).....
其实在赛场和剑神坤队讨论的算法就没问题,写一个简单的AI(就是题解所说的对抗搜索)庆幸的是我高中接触过极其相似的----bingo,大概就是优先选择'x'较多的排或列或对角线注意也要关注较多的'O'排或列或对角线,关于剪枝就是每排每列有不同的妻子就可以终止(可以想一想为什么)
就是需要些大量的代码而且保持脑子不绕 这是一项技能。。。
这是标准程序:
1 // 1999 ACM Mid-Central Regional Programming Contest 2 // Problem A: Find the Winning Move 3 // by Dr. Eric Shade, Computer Science Department, SMSU 4 5 /** 6 * modified by neko13 7 */ 8 9 import java.io.*; 10 import java.util.*; 11 import static java.lang.System.*; 12 13 14 public class Main { 15 static final char SPACE = '.'; 16 static Scanner cin = new Scanner(in); 17 static char[] board; 18 19 public static void main(String args[]) throws IOException { 20 // ACMIO in = new ACMIO("win.in"); 21 // PrintWriter out = new PrintWriter(new FileWriter("win.out")); 22 23 for (String cmd = cin.nextLine(); cmd.equals("?"); cmd = cin.nextLine()) { 24 String a = cin.nextLine(); 25 String b = cin.nextLine(); 26 String c = cin.nextLine(); 27 String d = cin.nextLine(); 28 String e = a+b+c+d; 29 board = e.toCharArray(); 30 31 // show(); 32 33 int k = findForcedWin(); 34 35 if (k >= 0) 36 out.println("(" + k/4 + "," + k%4 + ")"); 37 else 38 out.println("#####"); 39 } 40 41 out.close(); 42 } 43 44 45 public static int findForcedWin() { 46 for (int i = 0; i < 16; ++i) 47 if (board[i] == SPACE && xForcedWinPlaying(i)) 48 return i; 49 50 return -1; 51 } 52 53 54 public static boolean xForcedWinPlaying(int i) { 55 board[i] = 'x'; 56 57 if (! isWin(i, 'x')) { 58 for (int j = 0; j < 16; ++j) { 59 if (board[j] == SPACE && ! oForcedLossPlaying(j)) { 60 board[i] = SPACE; 61 return false; 62 } 63 } 64 } 65 66 board[i] = SPACE; 67 return true; 68 } 69 70 71 public static boolean oForcedLossPlaying(int j) { 72 board[j] = 'o'; 73 74 if (! isWin(j, 'o')) { 75 for (int i = 0; i < 16; ++i) { 76 if (board[i] == SPACE && xForcedWinPlaying(i)) { 77 board[j] = SPACE; 78 return true; 79 } 80 } 81 } 82 83 board[j] = SPACE; 84 return false; 85 } 86 87 88 public static boolean isWin(int i, char player) { 89 int r = 4 * (i / 4); 90 int c = i % 4; 91 92 return (board[r ] == player && board[r + 1] == player && 93 board[r + 2] == player && board[r + 3] == player) 94 || (board[c ] == player && board[c + 4] == player && 95 board[c + 8] == player && board[c +12] == player) 96 || (board[ 0] == player && board[ 5] == player && 97 board[10] == player && board[15] == player) 98 || (board[ 3] == player && board[ 6] == player && 99 board[ 9] == player && board[12] == player); 100 } 101 102 103 public static void show() { 104 for (int i = 0; i < 16; ++i) { 105 System.out.print(board[i]); 106 if (i%4 == 3) System.out.println(); 107 } 108 } 109 }
幸运数
如果A,B是幸运数那么A+B+2也是幸运数 现在给你A B C已知A B是幸运数请问C是不是幸运数
//以下是原题解 我老是感觉那里错了......难道是我的问题?
幸运数:c=a+b+2可以化为(c+2)=(a+2)+(b+2),即c=a+b;所以任何一个幸运数都是由最初的两个幸运数所组成的,即c=x*a+y*b。
//另外刚开始我也理解错了,(其实都怪领导!)以为简单判断a+b+2==c就行了 但是忘记了c==a+a+2 c==b+b+2 c==(a+b+2)+a+2 c==(a+b+2)+b+2.........一系列的情况
我的题解
我们就先把a,b叫基本元, 不难看出c-2是由两个基本元组成的 c-4是三个 c-6是四个。。。。 所以我们从c-2开始 到 min(a,b)结束(不包括) 遍历一遍,然后在每次遍历中我们在判断是否可以写成 nx+my形式就可以了
大概是这样:c-2*p=nx+my (n+m=p)
代码嘛。。。
void fun1()
{
if (有时间) 补上;
}
fun1();
//更新 ----这是标程 和我的思想不一样。。。
1 #include<iostream> 2 3 using namespace std; 4 5 int gcd(int x,int y) 6 { 7 if(!x || !y) return x>y?x:y; 8 for(int t;t=x%y;x=y,y=t); 9 return y; 10 } 11 12 int main() 13 { 14 int t,a,b,c; 15 cin>>t; 16 while(t--) 17 { 18 cin>>a>>b>>c; 19 a+=2;b+=2;c+=2; 20 int g=a*b/gcd(a,b); 21 int n=c/a,m=c%a; 22 while(m%b) 23 { 24 if(n==0) break; 25 n--; 26 g-=a; 27 if(g==0) break; 28 m+=a; 29 } 30 if(m%b) cout<<"No."<<endl; 31 else cout<<"Yes."<<endl; 32 } 33 return 0; 34 }
大水题我就不说了
遍历一遍找到最大最小下标 然后cout
给了 r1 r2 r3 求三角形ABC面积
呵呵,数学题我还是....贴文献吧
http://wenku.baidu.com/link?url=Tly1I1zFpQ9pFBRZ4kDHM9xfiBlSyuvExgdakBsk4oAw_KLxCZSKX05j4UP16P7kqd8-A6ZLHJ06tRKx9eLN2ufhsM7NQ347NC_ZiIWgna3
三角形:用向量法求出三个圆的圆心,然后即可求出三条切线。
#include<iostream> #include<cmath> #include<cstdio> #define sqr(a) ((a)*(a)) using namespace std; const double eps=1e-8; const double pi=2.0*asin(1.0); double getangle(double a,double b,double c) { return acos((sqr(a)+sqr(b)-sqr(c))/(2*a*b)); } double getangle(double a,double b) { return asin((a-b)/(a+b)); } typedef struct point { double x,y; point(double xx=0,double yy=0):x(xx),y(yy){} }vector; point operator + (point a,vector b) { return point(a.x+b.x,a.y+b.y); } vector operator - (point a,point b) { return vector(a.x-b.x,a.y-b.y); } vector operator * (vector a,double b) { return vector(a.x*b,a.y*b); } double dot(vector a,vector b) { return a.x*b.x+a.y*b.y; } double cross(vector a,vector b) { return a.x*b.y-a.y*b.x; } vector rotate(vector a,double b) { double s=sin(b),c=cos(b); return vector(a.x*c-a.y*s,a.x*s+a.y*c); } double len(vector a) { return sqrt(sqr(a.x)+sqr(a.y)); } vector resize(vector a,double b) { b/=len(a); return vector(a.x*b,a.y*b); } point inter(point a,vector v,point c,vector w) { vector u=a-c; double t=cross(w,u)/cross(v,w); return a+v*t; } int main() { double r1,r2,r3; int t; cin>>t; for(int i=1;i<=t;i++) { cin>>r1>>r2>>r3; point c1,c2,c3; c1=point(0,r1); c2=point(sqrt(sqr(r1+r2)-sqr(r1-r2)),r2); double a=r1+r2,b=r2+r3,c=r3+r1; c3=inter(c1,rotate(c2-c1,getangle(c,a,b)),c2,rotate(c1-c2,-getangle(a,b,c))); vector v1=vector(1,0),v2=vector(rotate(c3-c2,getangle(r2,r3))),v3=vector(rotate(c1-c3,getangle(r3,r1))); if(cross(v1,v2)<eps || cross(v2,v3)<eps || cross(v3,v1)<eps) { printf("No Solution!\n");continue; } point p1=point(0,0),p2=c2+resize(rotate(v2,-pi/2),r2),p3=c3+resize(rotate(v3,-pi/2),r3); point pa=inter(p1,v1,p3,v3),pb=inter(p2,v2,p1,v1),pc=inter(p3,v3,p2,v2); double s=cross(pb-pa,pc-pa)/2; printf("%.3lf\n",s); } }
中心点
给出若干个点p1 p2...pn的坐标 有一个点
这个点到p1p2 ...pn距离和最小,求最小值
原题
http://poj.org/problem?id=2420
// 模拟退火求费马点(随机算法, 要求精度足够)
和我的想法完全不同....我就不贴我的代码了 完全错误...
ps:费马点就是在把这个题目的若干个点改为3个点,本题为费马点的推广....
1 #include <iostream> 2 #include <cmath> 3 #include <iomanip> 4 using namespace std; 5 6 double x[100], y[100]; 7 int N; 8 9 double test(double xx, double yy) { 10 double total = 0; 11 for (int i=0;i<N;i++) 12 total+=sqrt(pow(x[i]-xx,2)+pow(y[i]-yy,2)); 13 return total; 14 } 15 16 int main() 17 { 18 double xx,yy; 19 double delta; 20 cin>>N; 21 for(int i=0;i<N;i++) 22 cin>>x[i]>>y[i]; 23 xx = 5000; 24 yy = 5000; 25 for (delta=5000;delta>0.1;delta*=0.9) { 26 if (test(xx,yy+delta) < test(xx,yy)) yy+=delta; 27 if (test(xx,yy-delta) < test(xx,yy)) yy-=delta; 28 if (test(xx+delta,yy) < test(xx,yy)) xx+=delta; 29 if (test(xx-delta,yy) < test(xx,yy)) xx-=delta; 30 } 31 cout<<setiosflags(ios::fixed); 32 cout<<setprecision(0)<<test(xx,yy)<<endl; 33 return 0; 34 }
博弈论
只要判断n==2^k-1 就行了 。。。。有一(大)部分头文件是无用的
#include <set> #include <map> #include <list> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <cassert> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> using namespace std; int grundy( int n ) { if( n == 1 ) return 0; if( n & 1 ) return grundy( n/2 ); return n/2; } int main() { int n; while( scanf("%d", &n) == 1 && n ) { printf("%s\n", grundy(n) ? "Alice" : "Bob"); } return 0; }
令人眼花缭乱的Dp //有时间再消化吧!
还是要吐槽一句考虑Dp算法的时候就怕想太多!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!其实根本没必要想那么多!!!
1 #include <set> 2 #include <map> 3 #include <list> 4 #include <cmath> 5 #include <ctime> 6 #include <deque> 7 #include <queue> 8 #include <stack> 9 #include <cctype> 10 #include <cstdio> 11 #include <string> 12 #include <vector> 13 #include <cassert> 14 #include <cstdlib> 15 #include <cstring> 16 #include <sstream> 17 #include <iostream> 18 #include <algorithm> 19 20 using namespace std; 21 22 const double inf = 1e50; 23 const int NN = 10005; 24 25 int n, P; 26 27 struct info { 28 int p1, p2, t1, t2, w1, w2; 29 }A[NN]; 30 31 double dp[2][101][7]; 32 33 int main() { 34 35 double cl = clock(); 36 while( scanf("%d %d", &n, &P) == 2 && n ) { 37 for( int i = 1; i <= n; i++ ) scanf("%d %d %d %d %d %d", &A[i].p1, &A[i].p2, &A[i].t1, &A[i].t2, &A[i].w1, &A[i].w2); 38 39 for( int i = 1; i <= 100; i++ ) for( int j = 0; j <= 6; j++ ) dp[0][i][j] = inf; 40 dp[0][P][0] = 0; 41 int cur = 1, prev = 0; 42 for( int k = 1; k <= n; k++ ) { 43 for( int i = 1; i <= 100; i++ ) for( int j = 0; j <= 6; j++ ) dp[cur][i][j] = inf; 44 45 for( int i = 1; i <= 100; i++ ) for( int j = 0; j <= 6; j++ ) if( dp[prev][i][j] < inf && i >= A[k].p1 ) { 46 int i1 = i + A[k].w1; 47 int j1 = j + A[k].w2; 48 49 if( i1 * (1 << j1) >= 100 ) i1 = 100, j1 = 0; 50 51 double r; 52 53 if( i >= A[k].p2 ) r = A[k].t2; 54 else r = A[k].t2 + (A[k].p2 - i + 0.) * ( A[k].t1 - A[k].t2 ) / (A[k].p2 - A[k].p1); 55 56 dp[cur][i1][j1] = min( dp[cur][i1][j1], r + dp[prev][i][j] ); 57 58 } 59 60 for( int j = 6; j > 0; j-- ) for( int i = 1; i <= 100; i++ ) if( dp[cur][i][j] < inf ) { 61 int i1 = min( i * 2, 100 ); 62 int j1 = j - 1; 63 dp[cur][i1][j1] = min( dp[cur][i1][j1], dp[cur][i][j] ); 64 } 65 66 swap( cur, prev ); 67 } 68 double res = inf; 69 for( int j = 6; j >= 0; j-- ) for( int i = 1; i <= 100; i++ ) res = min( res, dp[prev][i][j] ); 70 if(res > inf/2) printf("Impossible\n"); 71 else printf("%.2lf\n", res + 1e-11); 72 } 73 74 cl = clock() - cl; 75 fprintf(stderr, "Total Execution Time = %lf seconds\n", cl / CLOCKS_PER_SEC); 76 77 return 0; 78 }
有一个是给出图形计算面积的
这道题很简单啊 hahahahaha~
1每一行分解为一个小图形 最后加起来
对于每一行
2 刚开始如果出现'.'是不计入的一直到'/'或'\'出现 才计入,然而通过这个发现‘./.\./.\.’累计有奇数个/或\就计入 否则不计入
3 '.'代表1 '/''\'代表1/2不过可以保证'/''\'出现次数是偶数
这样就解出来了
fun1();
还有一个数论的问题
求
1^k+2^k+...+n^k mod 1000000007(1和7之间几个0忘记了,在7~10个范围中)
只用快速幂TLE,原因 : n<10000000000;
当然不应该傻乎乎的加啦 有通项公式的说!
这个通项公式是一个非常特别的
公式为
1^k+2^k+...+n^k=((n+1+p)^(k+1)-p^(k+1))/(k+1)
我们先要求一个数字p,p满足以下规则
(1+p)^(k+1)-p^(k+1)=0这个里面首先要展开,展开后对于p,p^2 p^3等,我们要当成一个整体对待,比如
k=1的时候
(1+p)^2-p^2=0
1+2p=0 p=-1/2
k=2的时候
(1+p)^3-p^3=0
1+3p+3p^2=0
其中p=-1/2,代入
p^2=1/6
也就是说,p p^2 p^3这些数字之间相对独立
我们来看看k=1的时候我们计算的通项
1+2+..+n=((n+1+p)^2-p^2)/2=((n+1)^2+2(n+1)p)/2
p=-1/2代入
=((n+1)^2-(n+1))/2=n(n+1)/2
我们来看k=2的时候
p=-1/2 p^2=1/6前面已经计算了,不再重复
1^2+2^2+....+n^2=((n+1+p)^3-n^3)/3
=((n+1)^3+3(n+1)^2*p+3(n+1)p^2)3
代入p,p^2
=((n+1)^3-3(n+1)^2/2+3*(n+1)/6)/3
=(n+1)((2(n+1)^2-3(n+1)+1)/6
=(n+1)((2n^2+4n+2-3n-3+1)/6
=(n+1)(2n^2+n)/6=n(n+1)(2n+1)/6
还有一个是一个简单题
素数间隙
给一个数 如果这个数是素数输出0 否则输出 比这个数大的素数中最小的数a1 和 比这个小的素数中最大的数a2 之差 a1-a2
两种做法
我用的打表+暴力, 或者线性素数筛+二分
http://poj.org/problem?id=3518
代码嘛。。。
fun1();
。。。。。结束了
while(1)
RP++;