- HDU 2516 取石子游戏
原题链接:Here!
思路:第一人败的情况是 n=2,3,5,8,13...... 是个斐波那契数列
代码:
/* Note: n=2 第一人败 * n=3 第一人败 * n=4 第二人败 n=5 第一人败 * n=6 第二人败 n=7 第二人败 n=8 第一人败 * n=9 第二人败 n=10 第二人败 n=11 第二人败 n=12 第二人败 n=13 第一人败 * 这就能很说明问题了 */ // #include<bits/stdc++.h> using namespace std; typedef long long LL; LL fb[1000]; int n,i; void init(){ // 打个第一人败的表 fb[0]=1; fb[1]=1; for(int i=2;i<1000;i++) fb[i]=fb[i-1]+fb[i-2]; } int main(){ init(); while(~scanf("%d",&n) && n){ for(i=2;i<1000 && n!=fb[i] ;i++); if(i==1000) printf("First win\n"); else printf("Second win\n"); } return 0; }
- HDU 1232 畅通工程
原题链接:Here!
思路:并查集模板
代码:
/* Note: 裸并查集 */ #include<bits/stdc++.h> using namespace std; const int maxn = 1000<<1; int f[maxn]; int n,m,a,b; int getf(int u){ if(u==f[u]) return u; f[u]=getf(f[u]); return f[u]; } void marge(int u,int v){ int f1,f2; f1=getf(u); f2=getf(v); if(f1!=f2) f[f2]=f1; } int main(){ while(~scanf("%d",&n) && n){ scanf("%d",&m); for(int i=0;i<=n;i++) f[i]=i; for(int i=0;i<m;i++){ scanf("%d%d",&a,&b); marge(a,b); } int cnt=0; for(int i=1;i<=n;i++) if(i==f[i]) cnt++; printf("%d\n",cnt-1); } return 0; }
- HDU 1427 速算24点 ( DP ) ***
原题链接:Here!
思路:用next_permutation()代替括号,深搜
代码:
#include<bits/stdc++.h> using namespace std; int res[4]; bool ok; void dfs(int sum,int cur,int tmp){ if(ok) return; if(cur==3){ if(sum+tmp==24) ok=1; if(sum-tmp==24) ok=1; if(sum*tmp==24) ok=1; if(tmp!=0 && sum%tmp==0 && sum/tmp==24) ok=1; // 保证分母不为0且能够整除 return; } dfs(sum+tmp,cur+1,res[cur+1]); dfs(sum-tmp,cur+1,res[cur+1]); dfs(sum*tmp,cur+1,res[cur+1]); if(tmp!=0 && sum%tmp==0) dfs(sum/tmp,cur+1,res[cur+1]); dfs(sum,cur+1,tmp+res[cur+1]); dfs(sum,cur+1,tmp-res[cur+1]); dfs(sum,cur+1,tmp*res[cur+1]); if(res[cur+1]!=0 && tmp%res[cur+1]==0) dfs(sum,cur+1,tmp/res[cur+1]); } int main(){ char s[3]; while(1){ for(int i=0;i<4;i++){ if(scanf("%s",s)==EOF) return 0; if(s[0]=='A') res[i]=1; else if(s[0]=='1' && s[1]=='0') res[i]=10; else if(s[0]=='J') res[i]=11; else if(s[0]=='Q') res[i]=12; else if(s[0]=='K') res[i]=13; else res[i]=s[0]-'0'; } sort(res,res+4); ok=0; do{ dfs(res[0],1,res[1]); }while(next_permutation(res,res+4) && !ok); if(ok) printf("Yes\n"); else printf("No\n"); } return 0; }
- HDU 2059 龟兔赛跑 ( DP ) ***
原题链接:Here!
思路:dp[i] 代表到达第i个充电站的最短时间,dp[i] 可以由状态 dp[j] + T(j~i)转移得到,如果充电注意加上充电时间
代码:
/* Note: DP 状态转移方程 dp[i] 可以由状态 dp[j] + T(j~i)转移得到 */ #include<bits/stdc++.h> using namespace std; const int maxn = 1000+10; const int INF = 0x3f3f3f; int L,N,C,T,VR,VT1,VT2; double dp[maxn]; int dis[maxn]; void DP(){ memset(dp,-1,sizeof(dp)); dp[0]=0; for(int i=1;i<=N+1;i++){ double Min = INF , ans = 0; for(int j=0;j<i;j++){ int L=dis[i]-dis[j]; if(L>C) // 一次充电无法到达 ans = C*1.0/VT1 + (L-C)*1.0/VT2; else ans = L*1.0/VT1; ans += dp[j]; if(j) ans += T; // 如果充电加上充电时间 if(Min>ans) Min=ans; } dp[i]=Min; } } int main(){ while(scanf("%d",&L)!=EOF){ scanf("%d%d%d",&N,&C,&T); scanf("%d%d%d",&VR,&VT1,&VT2); for(int i=1;i<=N;i++) scanf("%d",&dis[i]); dis[0]=0; dis[N+1]=L; DP(); if(1.0*L/VR < dp[N+1]) printf("Good job,rabbit!\n"); else printf("What a pity rabbit!\n"); } return 0; }
- HDU 2206 IP计算
原题链接:Here!
思路:注意判断IP地址出错的情况即可
代码:
/* Note: IP地址被.分成4部分 容易出错的地方是 1.并没有分成4部分,间隔符不是3个 2.出现非法字符 3.数字没有在0~255之间 4.输入可能有空格 5.可能出现.111.11.1这种情况 */ #include<bits/stdc++.h> using namespace std; char ip[110]; bool ok; int main(){ while(gets(ip)){ ok=true; int len=strlen(ip); int cnt=0; if(len>15) ok=false; for(int i=0;i<len;i++){ if(ip[i]=='.') cnt++; else if(ip[i]>='0' && ip[i]<='9') continue; else{ ok=false; break; } } int t_sum=0; for(int i=0;i<len;i++){ if(ip[i]>='0' && ip[i]<='9') t_sum = t_sum*10 + ip[i]-'0'; if(ip[i]=='.' || i==len-1){ if(t_sum>255){ ok=false; break; } else t_sum=0; } } if( cnt != 3 || ip[0]<'0' || ip[0]>'9') ok=false; // 特判间隔符和出现 .111.11.1这种情况 if(ok) printf("YES\n"); else printf("NO\n"); } return 0; }
- HDU 2566 统计硬币
原题链接:Here!
代码:
/* Note: i j k 分别代表1 2 5 分硬币个数 逗#问题 */ #include<bits/stdc++.h> using namespace std; int main(){ int t; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m); int cnt=0; for(int j=0 ; j<=n ; j++){ for(int k=0 ; k<=n ; k++){ if(m-2*j-5*k>=0 && (j+k+m-2*j-5*k==n)) cnt++; } } printf("%d\n",cnt); } return 0; }
- HDU 1736 美观化文字
原题链接:Here!
思路: Hint 1.你可以认为所有中文字符由两个字节组成 2.string 重载过 + 这一点很好用
代码:
/* Note: 注意得用gets读,题目介绍是一段话,这段话会有控制符(换行、空格、制表符),所以用gets 题目可能会出现中文引号,如果出现中文引号需要记录出现几次,后面进行匹配 这个引号匹配很无语,要求不严格,也没办法严格要求,毕竟是随意输入的一段话 */ #include<bits/stdc++.h> using namespace std; //#define test const int maxn = 100000<<1; char str[maxn]; int main(){ #ifdef test freopen("testData.txt","r",stdin); #endif while(gets(str)){ int L=strlen(str); int cnt=0; for(int i=0;i<L;i++){ string tmp=""; // string 重载过+ 很好用 tmp = tmp+str[i]+str[i+1]; // 特殊判断中文引号所需的变量,还可以先用一个程序看一下中文引号的ASCII码直接对比ASCII也行 if(tmp=="“"|| tmp=="”") cnt++; // 特殊记录字符串中是否出现过中文引号 if(str[i]=='"'){ if(cnt%2==0) printf("“"); else printf("”"); cnt++; } else if(str[i]==',') printf(","); else if(str[i]=='.') printf("。"); else if(str[i]=='!') printf("!"); else if(str[i]=='?') printf("?"); else if(str[i]=='<' && str[i+1]=='<') printf("《"),i++; else if(str[i]=='>' && str[i+1]=='>') printf("》"),i++; else printf("%c",str[i]); // 除转化的字符其余正常输出 } printf("\n"); } return 0; }
- HDU 1577 WisKey的眼神
原题链接:Here!
思路:简单的建立个直线方程
代码:
/* Note: 建立直线方程 y = [(ey-sy)/(ex-sx)]*(x-sx)+sy 非常简单,只需要在开区间(sx,ex)内的存在一个y是整数就不能看到,否则就能看到 */ #include<bits/stdc++.h> using namespace std; int L,sx,sy,ex,ey; int main(){ while(scanf("%d",&L)!=EOF && L){ scanf("%d%d%d%d",&sx,&sy,&ex,&ey); if( ex>L || ey>L || ex<-L || ey<-L ) printf("Out Of Range\n"); else{ bool ok=true; if(sx==ex){ // 特殊判断是否在竖轴上 if(abs(sy-ey)>1) ok=false; } // 接下来能够判断是否在横轴上和斜方向 else{ int x1,x2; x1=min(sx,ex); x2=max(sx,ex); for(int i=x1+1;i<x2;i++){ if( (abs(ey-sy)*abs(i-sx)) % abs(ex-sx) == 0 ) {ok=false;break;} } } if(ok) printf("Yes\n"); else printf("No\n"); } } return 0; }
- HDU 1574 RP问题 ( DP ) ***
原题链接:Here!
思路:找到状态转移方程dp[i+a]=max(dp[i+a],dp[i]+c) ,还是弱啊,得苦练
代码:
#include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f; int dp[10020<<1]; // 因为人品最高消耗也就是10000,数组下标不能有负号,右移一倍 int T,n,a,b,c; void DP(){ } int main(){ while(scanf("%d",&T)!=EOF){ while(T--){ scanf("%d",&n); for(int i=0;i<20040;i++) dp[i] = -INF; int l=10000 , r=10000; // 定义左右两个游标 dp[10000]=0; for(int i=0;i<n;i++){ scanf("%d%d%d",&a,&b,&c); b += 10000; // RP门栏值需要右移10000 if(a<0){ // 如果这件事情是RP下降 C上升 只能是当前RP值大于RP门栏值 for(int i=b;i<=r;i++) dp[i+a]=max(dp[i+a],dp[i]+c); l+=a; } else{ for(int i=b;i>=l;i--) dp[i+a]=max(dp[i+a],dp[i]+c); r+=a; } } int ans = -INF; for(int i=l;i<=r;i++) ans=max(ans,dp[i]); printf("%d\n",ans); } } return 0; }
- HDU 2037 今年暑假不AC
原题链接:Here!
思路:典型 选择最多不相交区间问题
代码:
/* Note: 今年暑假不AC 非常明显的选择不相交区间问题 给出n个区间,尽可能多的选出不相交区间 首先对区间尾进行排序, */ #include<bits/stdc++.h> using namespace std; const int maxn = 100<<1; struct info{ int s,e; }Time[maxn]; int n; bool cmp(info a,info b){ return a.e<b.e; } int main(){ while(scanf("%d",&n)!=EOF && n){ for(int i=0;i<n;i++) scanf("%d%d",&Time[i].s,&Time[i].e); sort(Time,Time+n,cmp); // for(int i=0;i<=n;i++) printf("s = %d, e = %d\n",Time[i].s,Time[i].e); int cnt=1,Mark=0; // Mark一下上一次选择的节目 for(int i=1;i<n;i++){ if(Time[i].s>=Time[Mark].e) cnt++,Mark=i; } printf("%d\n",cnt); } return 0; }
- HDU 2074 叠筐
原题链接:Here!
思路:模拟
代码:
/* Note: 小模拟 NxN 奇整数矩形 填字符 注意N=1时 */ #include<bits/stdc++.h> using namespace std; const int maxn = 100; char G[maxn][maxn]; int n; char s1,s2; int main(){ int kase=0; while(scanf("%d %c %c",&n,&s1,&s2)!=EOF){ if(kase) printf("\n"); kase++; int temp=(n+1)/2; char str; if(temp%2) str=s1; else str=s2; if(n==1) printf("%c\n",s1); else{ for(int k=0;k<temp;k++){ for(int i=k;i<n-k;i++){ for(int j=k;j<n-k;j++){ G[i][j]=str; } } str=str==s1?s2:s1; } G[0][0]=G[0][n-1]=G[n-1][0]=G[n-1][n-1]=' '; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ printf("%c",G[i][j]); } printf("\n"); } } } return 0; }
- HDU 1106 排序
原题链接:Here!
思路:注意特殊情况,设置一个标记数组Mark[] 记录切割的位置
代码:
/* Note: 特殊情况 开头或者结尾有 5 511152225333555 */ #include<bits/stdc++.h> using namespace std; const int maxn = 1000+10; char str[maxn]; int Mark[maxn],ans[maxn]; int main(){ while(scanf("%s",&str)!=EOF){ memset(ans,0,sizeof(ans)); memset(Mark,-1,sizeof(Mark)); int L = strlen(str); int k = 0; Mark[0]=-1; for(int i=0;i<L;i++) if(str[i]=='5') Mark[++k]=i; Mark[++k]=L; // for(int i=0;i<=k;i++) printf("%d%c",Mark[i],i==k?'\n':' '); int s=0; for(int i=0;i<k;i++){ for(int j=Mark[i]+1;j<Mark[i+1];j++){ ans[s] = ans[s]*10 + str[j] - '0'; } if(Mark[i]+1!=Mark[i+1]) // 去掉前后相邻的5的情况 s++; } sort(ans,ans+s); for(int i=0;i<s;i++){ printf("%d%c",ans[i],i==s-1?'\n':' '); } } return 0; }
2017 寒假练习题 Part 1
最新推荐文章于 2022-12-20 10:02:05 发布