高温假闲着无聊,在voj上把CSU的机试题 刷了一道,可能是因为题目年代比较久远,题目的难度并不是很大。稍稍整理一下,希望以后用得着。
1264: 惠民工程
所有题目中唯一的数据结构题
一道最小生成树(MST)的模板题
MST问题的解法:Prim,Kruskal等
Description
市政府“惠民工程”的目标是在全市n个居民点间之架设煤气管道(但不一定有直接的管道相连,只要能间接通过管道可达即可)。很显然最多可架设 n(n-1)/2条管道,然而实际上要连通n个居民点只需架设n-1条管道就可以了。现请你编写程序,计算出该惠民工程需要的最低成本。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出居民点数目M ( < =100 )、 评估的管道条数 N;随后的 N 行对应居民点间管道的成本,每行给出一对正整数,分别是两个居民点的编号,以及此两居民点间管道的成本(也是正整数)。为简单起见,居民点从1到M编号。
Output
对每个测试用例,在1行里输出全市管道畅通所需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
Sample Input
3 3
1 2 1
1 3 2
2 3 4
3 1
2 3 2
Sample Output
3
?
Prim代码:
#include <stdio.h>
#define INF 0x7ffff
#define MAXVER 128
typedef struct graph
{
int adjMatrix[MAXVER][MAXVER];
int weight[MAXVER];
int vis[MAXVER];
} graph;
graph Graph;
int m,n;
void init()
{
for(int i=0; i<MAXVER; i++)
{
Graph.vis[i] = 0;
for(int j=0; j<MAXVER; j++)
if(i==j)
Graph.adjMatrix[i][j] = 0;
else
Graph.adjMatrix[i][j] = INF;
}
}
int prim()
{
int ans = 0;
for(int i=1; i<=m; i++)
Graph.weight[i] = Graph.adjMatrix[1][i];
Graph.vis[1] = 1;
for(int i=2; i<=m; i++)
{
int minCost = INF,idx;
for(int j=1; j<=m; j++)
if(!Graph.vis[j]&&minCost>Graph.weight[j])
{
minCost = Graph.weight[j];
idx = j;
}
if(minCost==INF)
return -1;
Graph.vis[idx] = 1;
ans+=Graph.weight[idx];
for(int j=1; j<=m; j++)
if(!Graph.vis[j]&&Graph.weight[j]>Graph.adjMatrix[idx][j])
Graph.weight[j] = Graph.adjMatrix[idx][j];
}
return ans;
}
int main()
{
while(~scanf("%d%d",&m,&n))
{
init();
for(int i=0; i<n; i++)
{
int src,dest,weight;
scanf("%d%d%d",&src,&dest,&weight);
Graph.adjMatrix[src][dest] = Graph.adjMatrix[dest][src] = weight;
}
int ans = prim();
(ans==-1)?printf("?\n"):printf("%d\n",ans);
}
return 0;
}
Kruskal代码:
#include <stdio.h>
#include <algorithm>
#define MAXVER 4096
int uSet[MAXVER];
int sum,ans;
struct edge
{
int src,dest,weight;
};
edge graph[MAXVER];
int cmp(edge a,edge b)
{
return a.weight<b.weight;
}
void MakeSet(int m)
{
for(int i=1; i<=m; i++)
uSet[i] = i;
}
int Find(int key)
{
if(key!=uSet[key])
key = Find(uSet[key]);
return key;
}
void Union(edge e)
{
if(Find(e.src)!=Find(e.dest))
{
uSet[Find(e.src)] = Find(e.dest);
sum++;
ans+=e.weight;
}
}
void Kruskal(int n)
{
sort(graph+1,graph+n+1,cmp);
for(int i=1; i<=n; i++)
Union(graph[i]);
}
int main()
{
int m,n;
while(~scanf("%d%d",&m,&n))
{
ans = sum = 0;
MakeSet(m);
for(int i=1; i<=n; i++)
scanf("%d%d%d",&graph[i].src,&graph[i].dest,&graph[i].weight);
Kruskal(n);
sum==m-1?printf("%d\n",ans):printf("?\n");
}
return 0;
}
1263: 最少钱币数
暴力枚举
Description
作为A公司的职员,最盼望的日子就是每月的8号了,因为这一天是发工资的日子,养家糊口就靠它了。但是对于公司财务处的工作人员来说,这一天则是很忙碌的一天,财务处的小胡最近就在考虑一个问题:如果每个员工的工资额都知道,最少需要准备多少张人民币,才能在给每位职员发工资的时候都不用老师找零呢?这里假设员工的工资都是正整数,单位元,人民币一共有100元、50元、10元、5元、2元和1元六种。
Input
输入数据包含多个测试实例,每个测试实例的第一行是一个整数n(n<100),表示老师的人数,然后是n个老师的工资(工资<5000)。
Output
每个测试用例输出一行,即凑成钱数值M最少需要的钱币个数。如果凑钱失败,输出“Impossible”。你可以假设,每种待凑钱币的数量是无限多的。
Sample Input
3
1 2 3
2
1 2
Sample Output
4
2
代码:
#include <stdio.h>
int main()
{
int money[6]= {100,50,10,5,2,1},n;
while(~scanf("%d",&n))
{
int ans = 0,salary = 0;
while(n--)
{
scanf("%d",&salary);
for(int i=0; i<6; i++)
if(salary/money[i])
ans+=salary/money[i],salary%=money[i];
}
printf("%d\n",ans);
}
return 0;
}
1262: 安全密码
按题目要求模拟就完事了~
Description
网络上各类交易活动越来越普及,为了能够安安心心地上网,经常需要设置一个安全的密码。一般来说一个比较安全的密码至少应该满足下面两个条件:
(1)密码长度大于等于8。
(2)密码中的字符应该来自下面“字符类别”中四组中的至少三组。
这四个字符类别分别为:
(1)大写字母:A,B,C…Z;
(2)小写字母:a,b,c…z;
(3)数字:0,1,2…9;
(4)特殊符号:~,!,@,#,$,%,^;
给你一个密码,你的任务就是判断它是不是一个安全的密码。
Input
输入数据有多组,每组占一行,每行一个密码(长度最大可能为50),密码仅包括上面的四类字符。
Output
对于每个测试实例,判断这个密码是不是一个安全的密码,是的话输出YES,否则输出NO。
Sample Input
a1b2c3d4
Linle@ACM
^~^@^@!%
Sample Output
NO
YES
NO
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int main()
{
char psw[99];
while(~scanf("%s",psw))
{
int len = strlen(psw);
if(len<8)
{
printf("NO\n");
continue;
}
int k1,k2,k3,k4;
k1 = k2 = k3 = k4 = 0;
for(int i=0; i<len; i++)
{
if(psw[i]>='A'&&psw[i]<='Z')
k1 = 1;
else if(psw[i]>='a'&&psw[i]<='z')
k2 = 1;
else if(psw[i]>='0'&&psw[i]<='9')
k3 = 1;
else
k4 = 1;
}
if(k1+k2+k3+k4>=3)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
1261: 水仙花数
初中的时候觉得这题好难( ̄▽ ̄)”
其实不要想太复杂就能做出
没思路的多半是想太多了
翻出了自己去年的AC代码作为反例奉劝大家想问题不要太复杂
Description
春天是鲜花灿烂的季节,水仙花就是其中最迷人的代表,数学上有个水仙花数,他是这样定义的:“水仙花数”是指一个三位数,它的各位数字的立方和等于其本身,比如:153=1^3+5^3+3^3。现在要求输出所有在m和n范围内的水仙花数。
Input
输入数据有多组,每组占一行,包括两个整数m和n(100<=m<=n<=999)。
Output
对于每个测试实例,要求输出所有在给定范围内的水仙花数,就是说,输出的水仙花数必须大于等于m,并且小于等于n,如果有多个,则要求从小到大排列在一行内输出,之间用一个空格隔开(注意每组输出的最后一个数之后不要加空格);如果给定的范围内不存在水仙花数,则输出no;每个测试实例的输出占一行。
Sample Input
100 120
300 380
Sample Output
no
370 371
去年代码(自己给自己加难度作死):
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n,m,x,y,z,sum;
vector<int> ans;
while(cin>>m>>n)
{
sum=0;
ans.clear();
for(int i=m; i<=n; i++)
{
x=i/100;
y=(i/10)%10;
z=i%10;
if((x*x*x)+(y*y*y)+(z*z*z)==i)
{
sum++;
ans.push_back(i);
}
}
if(sum==0)
cout<<"no";
for(vector<int>::iterator it=ans.begin(); it!=ans.end(); it++)
{
if(it!=ans.end())
cout<<*it<<" ";
else
cout<<*it;
}
cout<<endl;
}
return 0;
}
今年代码:
#include <stdio.h>
int main()
{
int i,j,k,m,n;
while(~scanf("%d%d",&m,&n))
{
int ans[99];
for(i=m,j=0; i<=n; i++)
{
int a,b,c;
a = i/100;
b = (i/10)%10;
c = i%10;
if(a*a*a+b*b*b+c*c*c==i)
ans[j++] = i;
}
if(j!=0)
{
for(int k=0; k<j-1; k++)
printf("%d ",ans[k]);
printf("%d\n",ans[j-1]);
}
else
printf("no\n");
}
return 0;
}
1260: 回文串问题
基本的字符串操作
暴力即可
Description
“回文串”是一个正读和反读都一样的字符串,字符串由数字和小写字母组成,比如“level”或者“abcdcba”等等就是回文串。请写一个程序判断读入的字符串是否是“回文”。
Input
输入包含多个测试实例,每一行对应一个字符串,串长最多100字母。
Output
对每个字符串,输出它是第几个,如第一个输出为”case1:”;如果一个字符串是回文串,则输出”yes”,否则输出”no”,在yes/no之前用一个空格。
Sample Input
level
abcde
noon
haha
Sample Output
case1: yes
case2: no
case3: yes
case4: no
代码:
#include <stdio.h>
#include <string.h>
int main()
{
char str[128],cnt = 0;
while(~scanf("%s",str))
{
int len = strlen(str),flag = 1;
for(int i=0; i<len/2; i++)
if(str[i]!=str[len-i-1])
flag = 0;
printf("case%d: %s\n",++cnt,flag?"yes":"no");
}
return 0;
}
总结
除了第一题属于数据结构内容以外,其他的都是C程序设计难度,所以编码的熟练度要求较高,第一题DeBug了很久才AC,如果放在考场上会很影响心态(T_T),这道MST其实只是个模板题理应一次AC,以后还是要多加练习啊…