- 1. 排座椅
【问题描述】
上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的D对同学上课时会交头接耳。
同学们在教室中坐成了 M 行 N 列,坐在第i行第j列的同学的位置是 (i,j) ,为了方便同学们进出,在教室中设置了 K 条横向的通道, L 条纵向的通道。于是,聪明的小雪想到了一个办法,或许可以减少上课时学生交头接耳的问题:她打算重新摆放桌椅,改变同学们桌椅间通道的位置,因为如果一条通道隔开了 2 个会交头接耳的同学,那么他们就不会交头接耳了。
请你帮忙给小雪编写一个程序,给出最好的通道划分方案。在该方案下,上课时交头接耳的学生的对数最少。
输入格式:
第一行,有 5 个用空格隔开的整数,分别是 M,N,K,L,D(2≤N,M≤1000,0≤K<M,0≤L<N,D≤2000)
接下来的 D行,每行有 4个用空格隔开的整数。第 i 行的 4 个整数 Xi,Yi,Pi,Qi,表示坐在位置 (Xi,Yi) 与 (Pi,Qi) 的两个同学会交头接耳(输入保证他们前后相邻或者左右相邻)。
输入数据保证最优方案的唯一性。
输出格式:
共两行。
第一行包含 K个整数 a1,a2,…,aK,表示第 a1 行和 a1+1 行之间、第 a2 行和 a2+1 行之间、…、第 aK 行和第 aK+1 行之间要开辟通道,其中 ai<ai+1,每两个整数之间用空格隔开(行尾没有空格)。
第二行包含 L 个整数 b1,b2,…,bL ,表示第 b1 列和 b1+1 列之间、第 b2 列和b2+1 列之间、…、第 bL 列和第 bL+1 列之间要开辟通道,其中 bi<bi+1 ,每两个整数之间用空格隔开(列尾没有空格)。
【输入样例】
4 5 1 2 3
4 2 4 3
2 3 3 3
2 5 2 4
【输出格式】
2
2 4
#include<iostream> #define N 1010 using namespace std; int m,n,k,l,d,x,y; int fx,fy,ansk,ansl,maxk = -1,maxl = -1; int vist[N][N],ak[N],al[N]; void findk(){//查找行 while(k--){ for(int i = 1; i < m; i++){ if(ak[i] != 1){ for(int j = 1; j < n; j++){ if(vist[i][j] && vist[i+1][j]){ ansk++; } } if(ansk > maxk){ maxk = ansk; fx = i; ansk = 0; } } } ak[fx] = 1; } } void findl(){ while(l--){ // 查找列 for(int i = 1; i < n; i++){ if(al[i] != 1){ for(int j = 1; j < m; j++){ if(vist[j][i] && vist[j][i+1]){ ansl++; } } if(ansl > maxl){ maxl = ansl; fy = i; ansl = 0; } } } al[fy] = 1; } } void print(){ for(int i = 1; i <= m; i++){ if(ak[i]){ cout << i << " "; } } cout << endl; for(int i = 1; i <= n; i++){ if(al[i]){ cout << i << " "; } } } int main() { cin >> m >> n >> k >> l >> d; for(int i = 1; i <= 2*d; i++){ cin >> x >> y; vist[x][y] = 1; } findk(); findl(); print(); return 0; } /* 4 5 1 2 3 4 2 4 3 2 3 3 3 2 5 2 4 */
- 2. 活动安排问题
【问题描述】
设有n(n<=100000)个活动的集合E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si <fi 。如果选择了活动i,则它在半开时间区间[si, fi)内占用资源。若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的。也就是说,当si≥fj或sj≥fi时,活动i与活动j相容。
活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合。
输入
每行2个整数(100000以内),用空格间隔。表示每个活动的起始和结束时间。最后一行是2个0,表示所有输入的结束。
输出
一个整数,表示最多能安排几个活动。
【样例输入】
1 2
1 4
1 3
2 3
0 0
【样例输出】
2
#include<iostream> #include<algorithm> using namespace std; struct data{ int b,d; }a[100001]; int gz(const data &a,const data &b) { if(a.d<b.d)return 1; else return 0; } int main() { int i=0; while(cin>>a[i].b>>a[i].d) { if(a[i].b==0&&a[i].d==0){i--;break;} i++; } sort(a,a+i,gz); int end=0,ans=0; for(int j=0;j<=i;j++) if(a[j].b>=end) { end=a[j].d; ans++; } cout<<ans; return 0; } /* 1 5 1 3 2 3 3 4 6 7 1 4 8 9 0 0 */
【问题描述】
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。
输入:
输入两行,第一行是一个整数n(1< =n< =10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1< =ai< =20000)是第i种果子的数目。
输出:
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。
【输入样例】
3
1 2 9
【输出格式】
15
#include<iostream> #include<algorithm> using namespace std; int a[10010],n; void df(int x) { int i,t,q; q=x; for(i=q+1;i<=n;i++) { if(a[i]<a[q]) q=i; } swap(a[x],a[q]); } int main() { int i,sum; while(cin >> n) { sum=0; for(i=1;i<=n;i++) cin >> a[i]; df(1); df(2); for(i=2;i<=n;i++) { a[i]+=a[i-1]; sum+=a[i]; df(i); df(i+1); } cout << sum; } return 0; } /* 3 1 3 9 17 4 1 2 3 4 19 5 1 2 8 9 15 69 2 1 9 2 10 2 */