今年暑假不AC:http://acm.hdu.edu.cn/showproblem.php?pid=2037
一个简单的贪心例题:
思路:就是自己看:
1 #include <iostream> 2 3 using namespace std; 4 5 int main() 6 7 { 8 9 int a[100],b[100]; 10 11 int n; 12 13 int e=0; 14 15 int cont=0; 16 17 while(cin>>n&&n!=0){ 18 19 cont=0; 20 21 for(int i=0;i<n;i++) 22 23 cin>>a[i]>>b[i]; 24 25 for(int i=0;i<n;i++) 26 27 for(int j=i;j<n;j++) 28 29 { 30 31 if(b[i]>b[j]) 32 33 { 34 35 swap(b[i],b[j]); //交换位置 36 37 swap(a[i],a[j]); //虽然只是冒泡法,这个问题还不会超时! 38 39 } 40 41 } 42 43 //取第一个 44 45 cont++; 46 47 e=b[0]; 48 49 for(int i=1;i<n;i++){ 50 51 if(a[i]>=e) { 52 53 cont++; 54 55 e=b[i]; 56 57 } 58 59 } 60 61 cout<<cont<<endl; 62 63 } 64 65 return 0; 66 67 }
Radar Installationhttp://poj.org/problem?id=1328
也是贪心算法。
思路:先把每个点对应圆的取值范围表示出来,此题就转化成为线段相交的问题。之后就是左端排序,再求他们之间分成几块。
#include<stdio.h> #include<iostream> #include<algorithm> #include<math.h> using namespace std; int main() { int n,m,i,a[1005],b[1005],j,s,q=0,k=0,sd; double c[1005],d[1005],e[1005],h;//要用double型! while(scanf("%d %d",&n,&m)!=EOF) { q++;k=0; if(n==0&&m==0) break; for(i=0;i<n;i++) {scanf("%d %d",&a[i],&b[i]); if(b[i]>m) k=1; } if(k==1) printf("Case %d: -1 ",q);// else { for(i=0;i<n;i++) for(j=i;j<n;j++) { if(a[i]>a[j]) { swap(a[i],a[j]); swap(b[i],b[j]); } } for(i=0;i<n;i++) { c[i]=sqrt(m*m-b[i]*b[i]); } for(i=0;i<n;i++) { d[i]=a[i]-c[i]; e[i]=a[i]+c[i]; } s=1; h=e[0]; for(i=1;i<n;i++) if(d[i]>h) { h=e[i]; s++; } else if(e[i]<h) h=e[i]; printf("Case %d: %d ",q,s);} } return 0; }
Y2K Accounting Bug http://poj.org/problem?id=2586
题目难理解,但做起来不难。以下题意解释来自:優YoU http://user.qzone.qq.com/289065406/blog/1299234147
实际上;只要讨论5种情况即可;(任一月固定盈余s,或固定亏损d).
SSSSDSSSSDSS 4s<d 保证“连续5个月必亏损”,每连续5个月种至少1个月D,
保证可能有全年最大盈余,每连续5个月中至多4个月S
SSSDDSSSDDSS 3s<2d 保证“连续5个月必亏损”,每连续5个月种至少2个月D,
保证可能有全年最大盈余,每连续5个月中至多3个月S
SSDDDSSDDDSS 2s<3d 保证“连续5个月必亏损”,每连续5个月种至少3个月D,
保证可能有全年最大盈余,每连续5个月中至多2个月S
SDDDDSDDDDSD s<4d 保证“连续5个月必亏损”,每连续5个月种至少4个月D,
保证可能有全年最大盈余,每连续5个月中至多1个月S
DDDDDDDDDDDD s>=4d 保证“连续5个月必亏损”,每连续5个月种至少5个月D,
每月亏损,此情况全年必亏损
要注意的是,前4种情况都仅仅是“可能有全年的盈余”,而不是“一定有全年的盈余”。
但是若果一旦有盈余,必定是最大盈余
#include<iostream> #include<stdio.h> using namespace std; int main() { int n,m,t; while(scanf("%d %d",&n,&m)!=EOF) { if(n==0&&m==0) break; if(m>n*4) { t=n*10-m*2; if(t>0) printf("%d ",t); else printf("Deficit "); } else if(m*2>n*3) { t=n*8-m*4; if(t>0) printf("%d ",t); else printf("Deficit "); } else if(m*3>n*2) { t=n*6-m*6; if(t>0) printf("%d ",t); else printf("Deficit "); } else if(m*4>n) { t=n*3-m*9; if(t>0) printf("%d ",t); else printf("Deficit "); } else printf("Deficit "); } return 0; }
Minimal Coveragehttp://poj.org/problem?id=2620
照样的贪心的方法,但注意这里排序一定不能用冒泡法!!!!!直接超时!
题意就是:数轴上有n个闭区间[ai,bi],选择尽量少的区间覆盖一条指定的线段[s,t]。
本人第一次用sort()来排序,这里要用结构体。贪心的算法一般就是先排序,再从小到大找关系就行了。
#include<iostream> #include<stdio.h> #include<algorithm> using namespace std; struct line { int left; int right; }a1[100000]; bool comp(line i,line j) { if(i.left<j.left) return true;//这里是从小到大的排序。只要看left就行了,right跟着一起排的。正符合题意。要想从大到小就是把小于符号变成大于! return false;从这里似乎看出对于结构体的这种排序,如果只说明一种,其他就默认地跟着那样排了! } int main() { int n,a,b,d=0,i,j,x=0,w=0,h,y=0,max1=0,max2,c[100000]; scanf("%d",&n); while(scanf("%d %d",&a,&b)!=EOF) { if(a==0&&b==0) break; if(a<n&&b>0) {a1[d].left=a;a1[d].right=b;d++;} } sort(a1,a1+d,comp); for(;;) { y=0; max2=max1; max1=0; for(i=0;i<d;i++) { if(a1[i].left<=max2&&a1[i].right>max2) { if(a1[i].right>max1) { max1=a1[i].right;c[x]=i; } y=1; } } x++; if(y!=1) {w=1;break;} if(max1>=n) {w=2;break; } } if(w==1) printf("No solution "); if(w==2) { printf("%d ",x); for(i=0;i<x;i++) { printf("%d %d ",a1[c[i]].left,a1[c[i]].right); } } return 0; }
关于sort()一些常见用法:
sort(a,a+n);默认的从小到大排序;
等价于:
bool comp(int a,int b)
{
return a<b;
}
sort(a,a+10,comp);
而要从大到小排序:
bool comp(int a,int b)
{
return a>b;
}
sort(a,a+10,comp);