算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。
输入格式:
输入在一行中给出不含空格的中缀表达式,可包含+
、-
、*
、\
以及左右括号()
,表达式不超过20个字符。
输出格式:
在一行中输出转换后的后缀表达式,要求不同对象(运算数、运算符号)之间以空格分隔,但结尾不得有多余空格。
输入样例:
2+3*(7-4)+8/4
输出样例:
2 3 7 4 - * + 8 4 / +
这种特判题还是不太熟练,回去反省,需要考虑+2,-3,1.5
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 char s[25],a[25]; 7 scanf("%s",a); 8 int l=strlen(a),f=0,c=0; 9 map<char,int>p;//判断运算符优先级 10 p['+']=p['-']=1; 11 p['*']=p['/']=2; 12 p['(']=p[')']=3; 13 for(int i=0;i<l;i++) 14 { 15 if((i<1||a[i-1]=='(')&&(a[i]=='+'||a[i]=='-')||a[i]=='.'||a[i]>='0'&&a[i]<='9') 16 { 17 if(f++)printf(" "); 18 if(a[i]!='+')printf("%c",a[i]);//(+2-3) -3+7 19 while(a[i+1]=='.'||a[i+1]>='0'&&a[i+1]<='9')i++,printf("%c",a[i]); 20 } 21 else 22 { 23 if(a[i]==')') 24 { 25 while(c&&s[c-1]!='(')printf(" %c",s[c-1]),c--; 26 c--; 27 } 28 else if(!c||p[a[i]]>p[s[c-1]])s[c++]=a[i]; 29 else 30 { 31 while(c&&s[c-1]!='(')printf(" %c",s[c-1]),c--; 32 s[c++]=a[i]; 33 } 34 } 35 } 36 while(c)printf(" %c",s[c-1]),c--; 37 return 0; 38 }
输入格式:
输入第一行给出物品个数N(<=1000);第二行给出N个正整数si(0<=si<=100,表示第i项物品的大小)。
输入样例:
8
60 70 80 90 30 40 10 20
输出样例:
60 1
70 2
80 3
90 4
30 1
40 5
10 1
20 2
5
按题意模拟
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 int n; 7 cin>>n; 8 int a[1005],s[1005]; 9 for(int i=1;i<=n;i++)cin>>a[i],s[i]=0; 10 int go[1005],p=0; 11 for(int i=1;i<=n;i++) 12 { 13 for(int j=1;j<=n;j++) 14 { 15 if(s[j]+a[i]<=100) 16 { 17 p=max(p,j); 18 go[i]=j; 19 s[j]+=a[i]; 20 break; 21 } 22 } 23 } 24 for(int i=1;i<=n;i++) 25 printf("%d %d\n",a[i],go[i]); 26 printf("%d\n",p); 27 return 0; 28 }
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。
输入格式:
输入数据包括城镇数目正整数N(<=1000)和候选道路数目M(<=3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。
输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。
输入样例:
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
输出样例:
12
最小生成树模板
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 struct edge 5 { 6 int u,v,w; 7 }e[3005]; 8 bool cmp(edge a,edge b) 9 { 10 return a.w<b.w; 11 } 12 int f[3005]; 13 int find(int x) 14 { 15 return f[x]==x?x:f[x]=find(f[x]); 16 } 17 int n,m; 18 int kru() 19 { 20 sort(e,e+m,cmp); 21 int ans=0,cnt=0; 22 for(int i=0;i<m;i++) 23 { 24 int fu=find(e[i].u); 25 int fv=find(e[i].v); 26 if(fu!=fv) 27 { 28 f[fu]=fv; 29 ans+=e[i].w; 30 if(++cnt==n-1)break; 31 } 32 } 33 if(cnt<n-1)return -1; 34 return ans; 35 } 36 int main() 37 { 38 cin>>n>>m; 39 for(int i=1;i<=n;i++)f[i]=i; 40 for(int i=0;i<m;i++) 41 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 42 printf("%d\n",kru()); 43 }
请编写程序帮助农夫计算将木头锯成N块的最少花费。
输入格式:
输入首先给出正整数N(<=104),表示要将木头锯成N块。第二行给出N个正整数(<=50),表示每段木块的长度。N个正整数(≤50),表示每段木块的长度。
输出格式:
输出一个整数,即将木头锯成N块的最少花费。
输入样例:
8
4 5 1 2 1 3 1 1
输出样例:
49
每次取最小两个合并
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 int n; 7 cin>>n; 8 priority_queue< int,vector<int>,greater<int> >q; 9 for(int i=0;i<n;i++) 10 { 11 int x; 12 cin>>x; 13 q.push(x); 14 } 15 int sum=0; 16 while(q.size()>=2) 17 { 18 int a=q.top(); 19 q.pop(); 20 int b=q.top(); 21 q.pop(); 22 sum+=a+b; 23 q.push(a+b); 24 } 25 printf("%d\n",sum); 26 return 0; 27 }
堆栈是一种经典的后进先出的线性结构,相关的操作主要有“入栈”(在堆栈顶插入一个元素)和“出栈”(将栈顶元素返回并从堆栈中删除)。本题要求你实现另一个附加的操作:“取中值”——即返回所有堆栈中元素键值的中值。给定 N 个元素,如果 N 是偶数,则中值定义为第 N/2 小元;若是奇数,则为第 (N+1)/2 小元。
输入格式:
输入的第一行是正整数 N(<=105)。随后 N 行,每行给出一句指令,为以下 3 种之一:
Push key
Pop
PeekMedian
其中 key
是不超过105的正整数;Push
表示“入栈”;Pop
表示“出栈”;PeekMedian
表示“取中值”。 的正整数Push
表示“入栈”;Pop
表示“出栈”;PeekMedian
表示“取中
对每个 Push
操作,将 key
插入堆栈,无需输出;对每个 Pop
或 PeekMedian
操作,在一行中输出相应的返回值。若操作非法,则对应输出 Invalid
。
输入样例:
17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop
输出样例:
Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid
pop和push操作直接用栈操作
由于N很大,中位数如果用数组移位插入删除会超时O(n),可以考虑二分[0,100000]然后用树状数组判断前面有几个比他小O(lognlogn)
总复杂度O(nlognlogn),有人说O(n^2)可以过,orz
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N=1e5+5; 5 int n=100000; 6 stack<int>st; 7 struct BIT{ 8 int sum[N]; 9 void init(){memset(sum,0,sizeof(sum));} 10 int lowbit(int x){return x&(-x);} 11 void update(int x,int w){for(int i=x;i<=n;i+=lowbit(i))sum[i]+=w;} 12 int query(int x){int ans=0;for(int i=x;i>0;i-=lowbit(i))ans+=sum[i];return ans;} 13 }T; 14 int main() 15 { 16 T.init(); 17 int q; 18 char op[25]; 19 scanf("%d",&q); 20 for(int i=1;i<=q;i++) 21 { 22 scanf("%s",op); 23 if(op[1]=='o') 24 { 25 if(st.empty())printf("Invalid\n"); 26 else printf("%d\n",st.top()),T.update(st.top(),-1),st.pop(); 27 } 28 else if(op[1]=='u') 29 { 30 int key; 31 scanf("%d",&key); 32 st.push(key); 33 T.update(key,1); 34 } 35 else 36 { 37 int cnt=((int)st.size()+1)/2; 38 if(cnt==0) 39 { 40 printf("Invalid\n"); 41 continue; 42 } 43 int L=0,R=100000; 44 while(L<R) 45 { 46 int mid=(L+R)>>1; 47 if(T.query(mid)>=cnt)R=mid; 48 else L=mid+1; 49 } 50 printf("%d\n",R); 51 } 52 } 53 return 0; 54 }
当你在社交网络平台注册时,一般总是被要求填写你的个人兴趣爱好,以便找到具有相同兴趣爱好的潜在的朋友。一个“社交集群”是指部分兴趣爱好相同的人的集合。你需要找出所有的社交集群。
输入格式:
输入在第一行给出一个正整数 N(<=1000),为社交网络平台注册的所有用户的人数。于是这些人从 1 到 N 编号。随后 N 行,每行按以下格式给出一个人的兴趣爱好列表:
Ki:hi[1]hi[2]...hi[Ki]
其中ki>0是兴趣爱好的个数,hi[j]是第j个兴趣爱好的编号,为区间 [1, 1000] 内的整数。
输出格式:
首先在一行中输出不同的社交集群的个数。随后第二行按非增序输出每个集群中的人数。数字间以一个空格分隔,行末不得有多余空格。
输入样例:
8
3: 2 7 10
1: 4
2: 5 3
1: 4
1: 3
1: 4
4: 6 8 1 5
1: 4
输出样例:
3
4 3 1
并查集,1-1000是兴趣的编号,1001-1000+n是人的编号
然后就是并查集模板了
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N=2005; 5 int f[N]; 6 int find(int x) 7 { 8 return f[x]==x?x:f[x]=find(f[x]); 9 } 10 int main() 11 { 12 int n,k,like; 13 cin>>n; 14 for(int i=1;i<=2000;i++)f[i]=i; 15 for(int i=1;i<=n;i++) 16 { 17 scanf("%d:",&k); 18 for(int j=1;j<=k;j++) 19 { 20 scanf("%d",&like); 21 f[find(like)]=f[find(i+1000)]; 22 } 23 } 24 bool vis[2005]={0}; 25 int cnt=0; 26 int sum[2005]={0}; 27 for(int i=1001;i<=1000+n;i++) 28 { 29 if(vis[i])continue; 30 int fa=f[find(i)]; 31 for(int j=i;j<=1000+n;j++) 32 { 33 if(fa==f[find(j)]) 34 { 35 sum[cnt]++; 36 vis[j]=true; 37 } 38 } 39 cnt++; 40 } 41 printf("%d\n",cnt); 42 sort(sum,sum+cnt); 43 for(int i=cnt-1;i>=0;i--) 44 printf("%d%c",sum[i],i==0?'\n':' '); 45 return 0; 46 }
某地老鼠成灾,现悬赏抓老鼠,每抓到一只奖励10元,于是开始跟老鼠斗智斗勇:每天在墙角可选择以下三个操作:放置一个带有一块奶酪的捕鼠夹(T
),或者放置一块奶酪(C
),或者什么也不放(X
)。捕鼠夹可重复利用,不计成本,奶酪每块3元。聪明的老鼠呢?它们每天可能会派出一只老鼠到墙角,看看墙角有啥:
- 若什么也没有(
X
),老鼠们就不高兴了(Unhappy),会有长达一天(也就是第二天)的不高兴期。在不高兴期间,不派出老鼠。不高兴期结束之后,派出老鼠。 - 若有捕鼠夹(
T
),这只老鼠被引诱吃掉奶酪并被打死(Dead),老鼠们会有长达两天(也就是第二和第三天)的伤心期。在伤心期间,不派出老鼠。伤心期结束之后,派出老鼠。在这种情况下,抓到1只老鼠可获得奖励10元,但同时也耗费了一块奶酪。注意,如果某一天放置了捕鼠夹但老鼠没有出现,则没有耗费奶酪。 - 若有奶酪(
C
),老鼠吃了奶酪会很开心(Happy!),会有长达两天(第二和第三天)的兴奋期。在兴奋期间,即使叠加了不高兴或者伤心,也必定派出老鼠。在这种情况下,没抓到老鼠,而且耗费了一块奶酪。注意,如果某一天放置了奶酪但老鼠没有出现,则奶酪可以下次再用,没有耗费。
现在给你连续几天的操作序列,且已知第一天肯定会派出老鼠,请判断老鼠每天的状态,并计算盈利。
输入格式:
输入在一行中给出连续的由C
或T
或X
组成的不超过70个字符的字符串,以$
结束。字符串中每个字符表示这一天的操作( 即X
:什么都不放;T
:放捕鼠夹;C
:放奶酪)。题目保证至少有一天的操作输入。
输出格式:
要求在第一行输出连续的字符串,与输入相对应,给出老鼠的状态:
!
表示派出老鼠吃到奶酪D
表示派出老鼠被打死U
表示派出老鼠无所获-
表示没有派出老鼠
第二行则应输出一个整数表示盈利。(如果有亏损,则是负数)
输入样例1:
TXXXXC$
输出样例1:
D--U-!
4
输入样例2:
CTTCCX$
输出样例2:
!DD--U
11
按题意模拟,水平不好代码有点长
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 string s; 7 cin>>s; 8 int cost=0,happy=0,unhappy=0; 9 for(int i=0;i<s.size();i++) 10 { 11 if(s[i]=='$')break; 12 if(s[i]=='X') 13 { 14 if(happy>0||(happy==0&&unhappy==0))//派出 15 { 16 printf("U"); 17 if(happy>0)happy--; 18 unhappy=-1; 19 } 20 else//未派出 21 { 22 if(unhappy<0)unhappy++; 23 if(happy<0)happy++; 24 printf("-"); 25 } 26 } 27 if(s[i]=='T') 28 { 29 if(happy>0||(happy==0&&unhappy==0)) 30 { 31 cost-=3; 32 printf("D");//抓到 33 if(happy>0)happy--; 34 unhappy=-2; 35 cost+=10; 36 } 37 else 38 { 39 if(unhappy<0)unhappy++; 40 if(happy<0)happy++; 41 printf("-"); 42 } 43 } 44 if(s[i]=='C') 45 { 46 if(happy>0||(happy==0&&unhappy==0)) 47 { 48 printf("!");//吃到奶酪 49 happy=2; 50 if(unhappy<0)unhappy++; 51 cost-=3; 52 } 53 else 54 { 55 if(unhappy<0)unhappy++; 56 if(happy<0)happy++; 57 printf("-"); 58 } 59 } 60 } 61 printf("\n%d",cost); 62 return 0; 63 }
HT[]
后,将得到HT[0]=3
,HT[1]=1
,HT[2]=2
的结果。
但是现在要求解决的是“逆散列问题”,即给定整数在散列表中的分布,问这些整数是按什么顺序插入的?
输入格式:
输入的第一行是正整数 N(<=1000),为散列表的长度。第二行给出了 N 个整数,其间用空格分隔,每个整数在序列中的位置(第一个数位置为0)即是其在散列表中的位置,其中负数表示表中该位置没有元素。题目保证表中的非负整数是各不相同的。
输出格式:
按照插入的顺序输出这些整数,其间用空格分隔,行首尾不能有多余的空格。注意:对应同一种分布结果,插入顺序有可能不唯一。例如按照顺序 3、2、1 插入长度为 3 的散列表,我们会得到跟 1、2、3 顺序插入一样的结果。在此规定:当前的插入有多种选择时,必须选择最小的数字,这样就保证了最终输出结果的唯一性。
输入样例:
11
33 1 13 12 34 38 27 22 32 -1 21
输出样例:
1 13 12 21 33 34 38 27 22 32
直接莽了个暴力,果然出奇迹
首先需要知道线性探测就是如果a[i]%n产生冲突就往后去找空的填(离散课)
然后就是把可以填的都找到,然后输出个最小的
O(n^3)~ 1e9嗯10ms
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int n,a[1005],has[1005]; 5 bool vis[1005]; 6 bool check(int h,int ok) 7 { 8 for(int i=0;(h+i)%n!=ok&&i<n;i++) 9 if(vis[(h+i)%n]==false) 10 return false; 11 return !vis[ok]; 12 } 13 int main() 14 { 15 int c=0; 16 scanf("%d",&n); 17 for(int i=0;i<n;i++) 18 { 19 scanf("%d",&a[i]); 20 has[i]=a[i]%n; 21 if(a[i]>=0)c++; 22 } 23 int ok[1005],ac[1005],pac=0; 24 while(pac<c) 25 { 26 int p=0,minn=1e9,xb=0; 27 for(int i=0;i<n;i++) 28 { 29 if(a[i]==-1||vis[i])continue; 30 if(check(has[i],i)) 31 { 32 if(minn>a[i]) 33 { 34 minn=a[i]; 35 xb=i; 36 } 37 } 38 } 39 ac[pac++]=minn; 40 vis[xb]=true; 41 } 42 for(int i=0;i<pac;i++) 43 printf("%d%c",ac[i],i==pac-1?'\n':' '); 44 return 0; 45 }
BCD数是用一个字节来表达两位十进制的数,每四个比特表示一位。所以如果一个BCD数的十六进制是0x12,它表达的就是十进制的12。但是小明没学过BCD,把所有的BCD数都当作二进制数转换成十进制输出了。于是BCD的0x12被输出成了十进制的18了!
现在,你的程序要读入这个错误的十进制数,然后输出正确的十进制数。提示:你可以把18转换回0x12,然后再转换回12。
输入格式:
输入在一行中给出一个[0, 153]范围内的正整数,保证能转换回有效的BCD数,也就是说这个整数转换成十六进制时不会出现A-F的数字。
输出格式:
输出对应的十进制数。
输入样例:
18
输出样例:
12
水题
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 int n; 7 cin>>n; 8 cout<<n/16*10+n%16; 9 return 0; 10 }
本题要求编写程序,计算2个正整数的和、差、积、商并输出。题目保证输入和输出全部在整型范围内。
输入格式:
输入在一行中给出2个正整数A和B。
输出格式:
在4行中按照格式“A 运算符 B = 结果”顺序输出和、差、积、商。
输入样例:
3 2
输出样例:
3 + 2 = 5
3 - 2 = 1
3 * 2 = 6
3 / 2 = 1
水题
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 int a,b; 7 cin>>a>>b; 8 printf("%d + %d = %d\n",a,b,a+b); 9 printf("%d - %d = %d\n",a,b,a-b); 10 printf("%d * %d = %d\n",a,b,a*b); 11 printf("%d / %d = %d\n",a,b,a/b); 12 return 0; 13 }
一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。假如兔子都不死,请问第1个月出生的一对兔子,至少需要繁衍到第几个月时兔子总数才可以达到N对?
输入格式:
输入在一行中给出一个不超过10000的正整数N。
输出格式:
在一行中输出兔子总数达到N最少需要的月数。
输入样例:
30
输出样例:
9
dp[i]表示第i天有多少对兔子
显然dp[i]=dp[i-1]+dp[i-2](昨天的+新出生的)
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 int n; 7 cin>>n; 8 int dp[22]={0}; 9 dp[1]=1; 10 dp[2]=1; 11 if(n==1)printf("%d\n",1); 12 else 13 { 14 for(int i=3;i<=21;i++) 15 { 16 dp[i]=dp[i-1]+dp[i-2]; 17 if(dp[i]>=n) 18 { 19 printf("%d\n",i); 20 break; 21 } 22 } 23 } 24 return 0; 25 }
本题要求编写程序,计算2个复数的和、差、积、商。
输入格式:
输入在一行中按照a1 b1 a2 b2
的格式给出2个复数C1=a1+b1i
和C2=a2+b2i
的实部和虚部。题目保证C2不为0。
输出格式:
分别在4行中按照(a1+b1i) 运算符 (a2+b2i) = 结果
的格式顺序输出2个复数的和、差、积、商,数字精确到小数点后1位。如果结果的实部或者虚部为0,则不输出。如果结果为0,则输出0.0。
输入样例1:
2 3.08 -2.04 5.06
输出样例1:
(2.0+3.1i) + (-2.0+5.1i) = 8.1i
(2.0+3.1i) - (-2.0+5.1i) = 4.0-2.0i
(2.0+3.1i) * (-2.0+5.1i) = -19.7+3.8i
(2.0+3.1i) / (-2.0+5.1i) = 0.4-0.6i
输入样例2:
1 1 -1 1.01
输出样例2:
(1.0+1.0i) + (-1.0+1.0i) = 0.0
(1.0+1.0i) - (-1.0+1.0i) = 2.0+2.0i
(1.0+1.0i) * (-1.0+1.0i) = -2.0i
(1.0+1.0i) / (-1.0+1.0i) = -1.0
大模拟,输出比较麻烦,这个精度误差EPS=0.1才可以过(跪了),除法考虑上下同乘共轭复数
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 double a1,b1,a2,b2; 5 void w(double a,char c,double b) 6 { 7 //输出前面的 8 if(b1>=0&&b2>=0)printf("(%.1lf+%.1lfi) %c (%.1lf+%.1lfi) = ",a1,b1,c,a2,b2); 9 else if(b1>=0&&b2<0)printf("(%.1lf+%.1lfi) %c (%.1lf%.1lfi) = ",a1,b1,c,a2,b2); 10 else if(b1<0&&b2>=0)printf("(%.1lf%.1lfi) %c (%.1lf+%.1lfi) = ",a1,b1,c,a2,b2); 11 else printf("(%.1lf%.1lfi) %c (%.1lf%.1lfi) = ",a1,b1,c,a2,b2); 12 if(fabs(a)<=1e-1&&fabs(b)<1e-1) 13 { 14 printf("0.0\n"); 15 return; 16 } 17 bool ok=0; 18 if(fabs(a)>1e-1)//a!=0 19 { 20 printf("%.1lf", a); 21 ok=1; 22 } 23 if(fabs(b)>1e-1)//b!=0 24 { 25 if(b>0&&ok)printf("+%.1lfi",b); 26 else printf("%.1lfi",b); 27 } 28 printf("\n"); 29 } 30 int main() 31 { 32 scanf("%lf%lf%lf%lf",&a1,&b1,&a2,&b2); 33 double a,b; 34 // + 35 a=a1+a2,b=b1+b2; 36 w(a,'+',b); 37 // - 38 a=a1-a2,b=b1-b2; 39 w(a,'-',b); 40 // * 41 a=a1*a2-b1*b2; 42 b=a1*b2+a2*b1; 43 w(a,'*',b); 44 // / 45 a=(a1*a2+b1*b2)/(a2*a2+b2*b2); 46 b=(a2*b1-a1*b2)/(a2*a2+b2*b2); 47 w(a,'/',b); 48 return 0; 49 }
本题要求编写程序,计算华氏温度100°F对应的摄氏温度。计算公式:C = 5 *(F-100)/9,式中:C表示摄氏温度,F表示华氏温度,输出数据要求为整型。
输入格式:
本题目没有输入。
输出格式:
按照下列格式输出
fahr = 100, celsius = 计算所得摄氏温度的整数值
通过计算得到C=37.7输出37即可,一开始输出了38(emmm)
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 printf("fahr = 100, celsius = 37"); 7 return 0; 8 }
本题要求编写程序,按照规定格式输出表格。
输入格式:
本题目没有输入。
输出格式:
要求严格按照给出的格式输出下列表格:
------------------------------------
Province Area(km2) Pop.(10K)
------------------------------------
Anhui 139600.00 6461.00
Beijing 16410.54 1180.70
Chongqing 82400.00 3144.23
Shanghai 6340.50 1360.26
Zhejiang 101800.00 4894.00
------------------------------------
水题
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 printf("------------------------------------\n"); 7 printf("Province Area(km2) Pop.(10K)\n"); 8 printf("------------------------------------\n"); 9 printf("Anhui 139600.00 6461.00\n"); 10 printf("Beijing 16410.54 1180.70\n"); 11 printf("Chongqing 82400.00 3144.23\n"); 12 printf("Shanghai 6340.50 1360.26\n"); 13 printf("Zhejiang 101800.00 4894.00\n"); 14 printf("------------------------------------\n"); 15 return 0; 16 }
2010年风靡全球的“水果忍者”游戏,想必大家肯定都玩过吧?(没玩过也没关系啦~)在游戏当中,画面里会随机地弹射出一系列的水果与炸弹,玩家尽可能砍掉所有的水果而避免砍中炸弹,就可以完成游戏规定的任务。如果玩家可以一刀砍下画面当中一连串的水果,则会有额外的奖励,如图1所示。
图 1
现在假如你是“水果忍者”游戏的玩家,你要做的一件事情就是,将画面当中的水果一刀砍下。这个问题看上去有些复杂,让我们把问题简化一些。我们将游戏世界想象成一个二维的平面。游戏当中的每个水果被简化成一条一条的垂直于水平线的竖直线段。而一刀砍下我们也仅考虑成能否找到一条直线,使之可以穿过所有代表水果的线段。
图 2
如图2所示,其中绿色的垂直线段表示的就是一个一个的水果;灰色的虚线即表示穿过所有线段的某一条直线。可以从上图当中看出,对于这样一组线段的排列,我们是可以找到一刀切开所有水果的方案的。
另外,我们约定,如果某条直线恰好穿过了线段的端点也表示它砍中了这个线段所表示的水果。假如你是这样一个功能的开发者,你要如何来找到一条穿过它们的直线呢?
输入格式:
输入在第一行给出一个正整数N
(<=104),表示水果的个数。随后N
行,每行给出三个整数x,y1,y2,其间以空格分隔,表示一条端点为(x,y1)和(x,y2)的水果,其中y1>y2。注意:给出的水果输入集合一定存在一条可以将其全部穿过的直线,不需考虑不存在的情况。坐标为区间[10-6,106)内的整数。
输出格式:
在一行中输出穿过所有线段的直线上具有整数坐标的任意两点p1(x1,y1),p2(x2,y2),格式为x1,y1,x2,y2。注意:本题答案不唯一,由特殊裁判程序判定,但一定存在四个坐标全是整数的解。
输入样例:
5
-30 -52 -84
38 22 -49
-99 -22 -99
48 59 -18
-36 -50 -72
输出样例:
-99 -99 -30 -52
首先如果线段X都相同(重合),那么就输出最小的上端点和最大的下端点
上图是通过对线段进行上下凸壳处理后的结果
上凸壳u维护一个栈,如果栈>=2并且p[i-1]在p[i-2]和p[i]的上方,就是(p[i]-p[i-1])X(p[i-2]-p[i-1])>0(叉积>0)
同理下凸壳d,叉积<0
根据题意,必然有解,那么上下凸壳不重合,答案就是图中灰色的虚线
通过观察能得到,答案可以在上下凸壳的折线上
枚举上凸壳的折线,那么下凸壳的点必然在折线下,叉积<0
同理枚举下凸壳
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define LL long long 5 #define fi first 6 #define se second 7 #define pa pair<int,int> 8 int n; 9 vector<int>p; 10 pa u[10000],d[10000]; 11 int uc,dc; 12 map<int,int>vis,up,down; 13 int lx,ly,rx,ry; 14 bool pupl(pa p1,pa p2,pa p3)//p2在p1p3上 15 { 16 return (LL)(p3.fi-p1.fi)*(p2.se-p1.se)-(LL)(p2.fi-p1.fi)*(p3.se-p1.se)>0; 17 } 18 bool pdownl(pa p1,pa p2,pa p3)//p2在p1p3下 19 { 20 return (LL)(p3.fi-p1.fi)*(p2.se-p1.se)-(LL)(p2.fi-p1.fi)*(p3.se-p1.se)<0; 21 } 22 int main() 23 { 24 int x,y1,y2; 25 scanf("%d",&n); 26 for(int i=0;i<n;i++) 27 { 28 scanf("%d%d%d",&x,&y1,&y2); 29 if(!vis[x]) 30 { 31 p.push_back(x); 32 vis[x]=1; 33 up[x]=y1; 34 down[x]=y2; 35 } 36 else 37 { 38 up[x]=min(up[x],y1); 39 down[x]=max(down[x],y2); 40 } 41 } 42 if(p.size()==1)lx=p[0],ly=up[p[0]],rx=p[0],ry=down[p[0]]; 43 else 44 { 45 sort(p.begin(),p.end()); 46 for(int i=0;i<p.size();i++) 47 { 48 while(uc>=2&&pupl(u[uc-2],u[uc-1],pa(p[i],up[p[i]])))uc--; 49 u[uc++]=pa(p[i],up[p[i]]); 50 while(dc>=2&&pdownl(d[dc-2],d[dc-1],pa(p[i],down[p[i]])))dc--; 51 d[dc++]=pa(p[i],down[p[i]]); 52 } 53 int i,j; 54 for(i=0;i<uc-1;i++) 55 { 56 for(j=0;j<dc;j++)//d[j]在u[i]和u[i+1]上NO 57 if(pupl(u[i],d[j],u[i+1]))break; 58 if(j==dc)break; 59 } 60 if(i==uc-1) 61 { 62 for(i=0;i<dc-1;i++) 63 { 64 for(j=0;j<uc;j++)//u[j]在d[i]和d[i+1]下NO 65 if(pdownl(d[i],u[j],d[i+1]))break; 66 if(j==uc)break; 67 } 68 lx=d[i].fi,ly=d[i].se,rx=d[i+1].fi,ry=d[i+1].se; 69 } 70 else 71 { 72 lx=u[i].fi,ly=u[i].se,rx=u[i+1].fi,ry=u[i+1].se; 73 } 74 } 75 printf("%d %d %d %d\n",lx,ly,rx,ry); 76 return 0; 77 }