NEU winter_training 1

水一下NEU的寒假作业
 

据老师说前八题太简单
简单带过好了
 
7-1
7-1 N个数求和
本题的要求很简单,就是求N个数字的和。麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式。

输入格式:
输入第一行给出一个正整数N(≤100)。随后一行按格式a1/b1 a2/b2 ...给出N个有理数。题目保证所有分子和分母都在长整型范围内。另外,负数的符号一定出现在分子前面。

输出格式:
输出上述数字和的最简形式 —— 即将结果写成整数部分 分数部分,其中分数部分写成分子/分母,要求分子小于分母,且它们没有公因子。如果结果的整数部分为0,则只输出分数部分。

输入样例1:
5
2/5 4/15 1/30 -2/60 8/3

      
    
输出样例1:
3 1/3

      
    
输入样例2:
2
4/3 2/3

      
    
输出样例2:
2

      
    
输入样例3:
3
1/3 -1/6 1/8

      
    
输出样例3:
7/24

      
    
作者: 陈越
单位: 浙江大学
时间限制: 400 ms
内存限制: 64 MB
7-1 N个数求和

分数求和,通分然后相加即可

注意下细节就可以了,比如整数和分数之间的空格什么时候加啊,得0怎么办啊,之类的
#include<iostream>
#include<cstdio>
using namespace std;
const long long N=101;
long long n,num[N][2];
long long d=1,dm=1,sum;
long long gcd(long long a,long long b){return b==0?a:gcd(b,a%b);}
long long lcm(long long a,long long b){
    long long g=gcd(a,b);
    return g*(a/g)*(b/g);
}
int main(){
    scanf("%lld",&n);
    for(long long i=1;i<=n;++i){
        scanf("%lld/%lld",&num[i][0],&num[i][1]);
        dm=lcm(dm,num[i][1]);
    }
    for(long long i=1;i<=n;++i){
        d=dm/num[i][1];
        sum+=num[i][0]*d;
    }
    if(!sum){printf("0");return 0;}
    if(sum/dm)printf("%lld",sum/dm);
    if(sum/dm && sum%dm)printf(" ");
    sum%=dm;
    
    if(sum<0){printf("-");sum=-sum;}
    long long g=gcd(sum,dm);
    sum/=g,dm/=g;
    if(sum)printf("%lld/%lld",sum,dm);
    return 0;
}
View Code
7-2
本题要求将输入的任意3个整数从小到大输出。

输入格式:
输入在一行中给出3个整数,其间以空格分隔。

输出格式:
在一行中将3个整数从小到大输出,其间以“->”相连。

输入样例:
4 2 8

      
    
输出样例:
2->4->8
7-2 比较大小

emmm...这怎么写都行吧

#include<iostream>
#include<cstdio>
using namespace std;

void swap(int *a,int *b){
    int temp=*a;
    *a=*b;
    *b=temp;
} 
int main(){
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    if(a>b)swap(a,b);
    if(a>c)swap(a,c);
    if(b>c)swap(b,c);
    printf("%d->%d->%d",a,b,c);
    return 0;
}
View Code

7-3

本题要求你计算A−B。不过麻烦的是,A和B都是字符串 —— 即从字符串A中把字符串B所包含的字符全删掉,剩下的字符组成的就是字符串A−B。

输入格式:
输入在2行中先后给出字符串A和B。两字符串的长度都不超过10
​4
​​ ,并且保证每个字符串都是由可见的ASCII码和空白字符组成,最后以换行符结束。

输出格式:
在一行中打印出A−B的结果字符串。

输入样例:
I love GPLT!  It's a fun game!
aeiou

      
    
输出样例:
I lv GPLT!  It's  fn gm!
7-3 A-B

遇到B中的字符不输出就行了。。。可能是钻了黑盒测试的空子吧

#include<iostream>
#include<cstdio>
#include<string> 
using namespace std;
const int N=10001;
bool del[300];
string s1,s2;
int main(){
    getline(cin,s1);getline(cin,s2);
    int len=s2.size();
    for(int i=0;i<len;++i)del[s2[i]]=1;
    len=s1.size();
    for(int i=0;i<len;++i)
        if(!del[s1[i]])putchar(s1[i]);
    return 0;
}
View Code

7-4

真的没骗你,这道才是简单题 —— 对任意给定的不超过10的正整数n,要求你输出2
​n
​​ 。不难吧?

输入格式:
输入在一行中给出一个不超过10的正整数n。

输出格式:
在一行中按照格式 2^n = 计算结果 输出2
​n
​​ 的值。

输入样例:
5

      
    
输出样例:
2^5 = 32
7-4 计算指数

。。。。

#include<iostream>
#include<cstdio>
#include<string> 
using namespace std;
int main(){
    int n;scanf("%d",&n);
    printf("2^%d = %d",n,1<<n);
    return 0;
}
View Code

7-5

对于给定的正整数N,需要你计算 S=1!+2!+3!+...+N!。

输入格式:
输入在一行中给出一个不超过10的正整数N。

输出格式:
在一行中输出S的值。

输入样例:
3

      
    
输出样例:
9
7-5 计算阶乘和

。。。。。

#include<iostream>
#include<cstdio>
#include<string> 
using namespace std;
long long sum,fac=1;
int main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;++i){
        fac*=i;
        sum+=fac;
    } 
    printf("%lld",sum);
}
View Code

7-6

这次真的没骗你 —— 这道超级简单的题目没有任何输入。

你只需要在一行中输出事实:This is a simple problem. 就可以了。
7-6 简单题

。。。。。。

#include<cstdio>

int main(){
    printf("This is a simple problem.");
    return 0;
}
View Code

7-7

美国总统奥巴马不仅呼吁所有人都学习编程,甚至以身作则编写代码,成为美国历史上首位编写计算机代码的总统。2014年底,为庆祝“计算机科学教育周”正式启动,奥巴马编写了很简单的计算机代码:在屏幕上画一个正方形。现在你也跟他一起画吧!

输入格式:
输入在一行中给出正方形边长N(3≤N≤21)和组成正方形边的某种字符C,间隔一个空格。

输出格式:
输出由给定字符C画出的正方形。但是注意到行间距比列间距大,所以为了让结果看上去更像正方形,我们输出的行数实际上是列数的50%(四舍五入取整)。

输入样例:
10 a

      
    
输出样例:
aaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaa
aaaaaaaaaa

      
7-7 跟奥巴马一起画方块

这个题是不是已经做过了。。。

#include<cstdio>

int n;
char c;
int main(){
    scanf("%d %c",&n,&c);
    for(int i=1;i<=(n+1)/2;++i){
        for(int j=1;j<=n;++j)
            putchar(c);
        if(i<(n+1)/2)putchar('\n');
    }
    return 0;
}
View Code

7-8

一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下:

首先对前17位数字加权求和,权重分配为:{7910584216379105842};然后将计算的和对11取模得到值Z;最后按照以下关系对应Z值与校验码M的值:

Z:0 1 2 3 4 5 6 7 8 9 10
M:1 0 X 9 8 7 6 5 4 3 2

      
    
现在给定一些身份证号码,请你验证校验码的有效性,并输出有问题的号码。

输入格式:
输入第一行给出正整数N(≤100)是输入的身份证号码的个数。随后N行,每行给出1个18位身份证号码。

输出格式:
按照输入的顺序每行输出1个有问题的身份证号码。这里并不检验前17位是否合理,只检查前17位是否全为数字且最后1位校验码计算准确。如果所有号码都正常,则输出All passed。

输入样例1:
4
320124198808240056
12010X198901011234
110108196711301866
37070419881216001X

      
    
输出样例1:
12010X198901011234
110108196711301866
37070419881216001X

      
    
输入样例2:
2
320124198808240056
110108196711301862

      
    
输出样例2:
All passed
7-8 查验身份证

嘛这个比起前面那几道还算是画风正常了一点(

然而本质还是一道模拟题

#include<cstdio>

char s[100][19];
bool error[100];
int n,cnt;
int cal[]={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
int check[]={1,0,'X',9,8,7,6,5,4,3,2};
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;++i){
        int sum=0;
        scanf("%s",s[i]);
        for(int j=0;j<17;++j)sum+=cal[j]*(s[i][j]-'0');
        if(s[i][17]!='X' && (s[i][17]-'0' != check[sum%11])){error[i]=1;++cnt;}
        if(s[i][17]=='X' && sum%11!=2){error[i]=1;++cnt;}
    }
    if(!cnt)printf("All passed");
    else{
        for(int i=0;i<n;++i)if(error[i]){
            printf("%s",s[i]);
            --cnt;
            if(cnt)printf("\n");
        }
        
    }
    return 0;
}
View Code

终于到了正片x

 
7-9 集合相似度
 

给定两个整数集合,它们的相似度定义为:/。其中Nc​​是两个集合都有的不相等整数的个数,Nt​​是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。

输入格式:

输入第一行给出一个正整数N(≤),是集合的个数。随后N行,每行对应一个集合。每个集合首先给出一个正整数M(≤),是集合中元素的个数;然后跟M个[区间内的整数。

之后一行给出一个正整数K(≤),随后K行,每行对应一对需要计算相似度的集合的编号(集合从1到N编号)。数字间以空格分隔。

输出格式:

对每一对需要计算的集合,在一行中输出它们的相似度,为保留小数点后2位的百分比数字。

输入样例:

3
3 99 87 101
4 87 101 5 87
7 99 101 18 5 135 18 99
2
1 2
1 3
 

输出样例:

50.00%
33.33%






排序去重然后计数就行了
qu水一下NEU的寒假作业
 
 
据老师说前八题太简单
简单带过好了
 
7-1
7-1 N个数求和
分数求和,通分然后相加即可
 
注意下细节就可以了,比如整数和分数之间的空格什么时候加啊,得0怎么办啊,之类的
View Code
 
 
7-2
7-2 比较大小
emmm...这怎么写都行吧
 
View Code
 
 
7-3
 
7-3 A-B
遇到B中的字符不输出就行了。。。可能是钻了黑盒测试的空子吧
 
View Code
 
 
7-4
 
7-4 计算指数
。。。。
 
View Code
 
 
7-5
 
7-5 计算阶乘和
。。。。。
 
View Code
 
 
7-6
 
7-6 简单题
。。。。。。
 
View Code
 
 
7-7
 
7-7 跟奥巴马一起画方块
这个题是不是已经做过了。。。
 
View Code
 
 
7-8
 
7-8 查验身份证
嘛这个比起前面那几道还算是画风正常了一点(
 
然而本质还是一道模拟题
 
View Code
 
 
终于到了正片x
 
 
7-9 集合相似度
 
给定两个整数集合,它们的相似度定义为:/。其中N​c​​是两个集合都有的不相等整数的个数,N​t​​是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。
 
输入格式:
输入第一行给出一个正整数N(≤),是集合的个数。随后N行,每行对应一个集合。每个集合首先给出一个正整数M(≤),是集合中元素的个数;然后跟M个[区间内的整数。
 
之后一行给出一个正整数K(≤),随后K行,每行对应一对需要计算相似度的集合的编号(集合从1到N编号)。数字间以空格分隔。
 
输出格式:
对每一对需要计算的集合,在一行中输出它们的相似度,为保留小数点后2位的百分比数字。
 
输入样例:
3
3 99 87 101
4 87 101 5 87
7 99 101 18 5 135 18 99
2
1 2
1 3
 
输出样例:
50.00%
33.33%
 
 
 
排序去重然后计数就行了
做题的时候忘了unique去重法qwq。做完题看群里dalao说才想起来
于是写了个很诡异甚至导致WA了好几发的去重
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int n,m[59],k,a[59][1009];
 7 int main(){
 8     scanf("%d",&n);
 9     for(int i=1;i<=n;++i){
10         scanf("%d",&m[i]);
11         for(int j=1;j<=m[i];++j)scanf("%d",&a[i][j]);
12         sort(a[i]+1,a[i]+m[i]+1);
13     }
14     scanf("%d",&k);
15     for(int i=1;i<=k;++i){
16         int a1,a2;
17         scanf("%d%d",&a1,&a2);
18         int p1=1,p2=1,nc=0,nt=0;
19         while(p1<m[a1]&&a[a1][p1]==a[a1][p1+1])++p1;
20         while(p2<m[a2]&&a[a2][p2]==a[a2][p2+1])++p2;
21         while(p1<=m[a1]&&p2<=m[a2]){
22 //            cout<<p1<<" "<<p2<<" ";
23             ++nt;
24             if(a[a1][p1]==a[a2][p2]){++nc,++p1,++p2;}
25             else{
26                 if(a[a1][p1]<a[a2][p2])++p1;
27                 else ++p2;
28             }
29             while(p1<m[a1]&&a[a1][p1]==a[a1][p1+1])++p1;
30             while(p2<m[a2]&&a[a2][p2]==a[a2][p2+1])++p2;
31         }
32         if(p1<=m[a1])nt+=m[a1]-p1+1;
33         if(p2<=m[a2])nt+=m[a2]-p2+1;
34         printf("%.2f%%",(double)nc/nt*100);
35         if(i<k)printf("\n");
36     }
37     return 0;
38 } 
View Code
7-10 树的遍历

给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。

输入格式:

输入第一行给出一个正整数(N≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。

输出格式:

在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

输入样例:

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
 

输出样例:

4 1 6 3 5 7 2


 
熟悉的二叉树入门题。。。
在后序遍历里找根,然后分治中序遍历
当时没写return居然能过样例emmmm
#include<cstdio>
#include<cstdlib>
#include<queue>
using namespace std;
const int N=301;
int n,post[N],in[N];
int root,ls[N],rs[N];
int work(int lp,int rp,int li,int ri){
//    printf("%d %d %d %d\n",lp,rp,li,ri);
//    system("pause");
    if(li==ri)return in[ri];
    int rt=post[rp];
    int k=li;while(in[k]!=rt)++k;
    int lenl=k-li;
    if(li<k)ls[rt]=work(lp,lp+lenl-1,li,k-1);
    if(k<ri)rs[rt]=work(lp+lenl,rp-1,k+1,ri);
    return rt;
}
queue<int>q;
void print(){
    while(!q.empty()){
        int x=q.front();q.pop();
        printf("%d",x);
        if(ls[x])q.push(ls[x]);
        if(rs[x])q.push(rs[x]);
        if(!q.empty())printf(" ");
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&post[i]);
    for(int i=1;i<=n;++i)scanf("%d",&in[i]);
    root=work(1,n,1,n);
    q.push(root);
    print();
    return 0;
}
View Code
 
 
7-11 家庭房产
 

给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。

输入格式:

输入第一行给出一个正整数N(≤),随后N行,每行按下列格式给出一个人的房产:

编号 父 母 k 孩子1 ... 孩子k 房产套数 总面积
 

其中编号是每个人独有的一个4位数的编号;分别是该编号对应的这个人的父母的编号(如果已经过世,则显示-1);k0k≤)是该人的子女的个数;孩子i是其子女的编号。

输出格式:

首先在第一行输出家庭个数(所有有亲属关系的人都属于同一个家庭)。随后按下列格式输出每个家庭的信息:

家庭成员的最小编号 家庭人口数 人均房产套数 人均房产面积
 

其中人均值要求保留小数点后3位。家庭信息首先按人均面积降序输出,若有并列,则按成员编号的升序输出。

输入样例:

10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100
 

输出样例:

3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000




建图跑dfs过的
后来dalao说用并查集。。。
仔细一想似乎就应该用并查集啊这题qwq场上没想起来
%%%dalao
有时间补个并查集解法吧
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=10009;
int p[N],cnt;
struct edge{int to,nex;}e[2000009];
void add(int u,int v){
    e[++cnt]=(edge){v,p[u]};
    p[u]=cnt; 
}
int n,famcnt;
double house[N],area[N];
bool vis[N],sign[N];
struct family{
    int people,minid;
    double house,area;
}fam[N];
bool cmp(family x,family y){
    if(fabs(x.area/x.people - y.area/y.people)<0.001)
        return x.minid<y.minid;
    return x.area/x.people > y.area/y.people;
}
void dfs(int id,int famid){
    vis[id]=1;++fam[famid].people;
    fam[famid].minid=min(fam[famid].minid,id);
    fam[famid].house+=house[id];
    fam[famid].area+=area[id];
    for(int i=p[id];i;i=e[i].nex){
        int v=e[i].to;
        if(!vis[v])dfs(v,famid);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        int id,fa,mo,k,kid;
        scanf("%d%d%d",&id,&fa,&mo);
        sign[id]=1;
        if(fa>=0){sign[fa]=1;add(id,fa);add(fa,id);}
        if(mo>=0){sign[mo]=1;add(id,mo);add(mo,id);}
        scanf("%d",&k);
        for(int j=1;j<=k;++j){
            scanf("%d",&kid);
            sign[kid]=1;
            add(id,kid);add(kid,id);
        }
        scanf("%lf%lf",&house[id],&area[id]);
//        printf("%lf %lf\n",house[id],area[id]);
    }
    for(int id=0;id<10000;++id)
        if(sign[id] && !vis[id]){
        fam[++famcnt].minid=id;
        dfs(id,famcnt);
    }
    printf("%d\n",famcnt);
    sort(fam+1,fam+famcnt+1,cmp);
    for(int i=1;i<=famcnt;++i){
        printf("%04d %d %.3f %.3f",fam[i].minid,fam[i].people,fam[i].house/fam[i].people,fam[i].area/fam[i].people);
        if(i!=famcnt)printf("\n");
    }
    return 0;
} 
View Code
 
7-12 最长对称子串
 

对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT&TAP s,于是你应该输出11。

输入格式:

输入在一行中给出长度不超过1000的非空字符串。

输出格式:

在一行中输出最长对称子串的长度。

输入样例:

Is PAT&TAP symmetric?
 

输出样例:

11


每个位置往两边搜
注意包括奇对称和偶对称
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

string s;
int main(){
    getline(cin,s);
    int len=s.size();
    int maxans=0;
    for(int i=0;i<len;++i){
        int ans=0;
        while(i-(ans+1)>=0 && i+(ans+1)<len && s[i-(ans+1)]==s[i+(ans+1)])++ans;
        maxans=max(ans*2+1,maxans);
    }
    for(int i=1;i<len;++i){
        int ans=0;
        while(i-1-(ans)>=0 && i+(ans)<len && s[i-1-(ans)]==s[i+(ans)])++ans;
        maxans=max(ans*2,maxans);
    }
    printf("%d",maxans);
    return 0;
    return 0;
} 
View Code
7-13 肿瘤诊断
 

在诊断肿瘤疾病时,计算肿瘤体积是很重要的一环。给定病灶扫描切片中标注出的疑似肿瘤区域,请你计算肿瘤的体积。

输入格式:

输入第一行给出4个正整数:M、N、L、T,其中M和N是每张切片的尺寸(即每张切片是一个M×N的像素矩阵。最大分辨率是1);L(≤)是切片的张数;T是一个整数阈值(若疑似肿瘤的连通体体积小于T,则该小块忽略不计)。

最后给出L张切片。每张用一个由0和1组成的M×N的矩阵表示,其中1表示疑似肿瘤的像素,0表示正常像素。由于切片厚度可以认为是一个常数,于是我们只要数连通体中1的个数就可以得到体积了。麻烦的是,可能存在多个肿瘤,这时我们只统计那些体积不小于T的。两个像素被认为是“连通的”,如果它们有一个共同的切面,如下图所示,所有6个红色的像素都与蓝色的像素连通。

输出格式:

在一行中输出肿瘤的总体积。

输入样例:

3 4 5 2
1 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
0 0 1 1
1 0 1 1
0 1 0 0
0 0 0 0
1 0 1 1
0 0 0 0
0 0 0 0
0 0 0 1
0 0 0 1
1 0 0 0
 

输出样例:

26
 
 
这个题第一眼的时候懵了。。。
后来仔细分析发现直接搜似乎就行
把每个肿瘤搜出来,统计答案的时候忽略那些比T小的就行了
dfs会爆空间。(这不应该是常识吗)
改的bfs
#include<iostream>
#include<cstdio> 
#include<queue>
using namespace std;
int map[1287][129][61];
bool vis[1287][129][61];
int V[5000000],cnt,sum;
int M,N,L,T;
struct node{int m,n,l;};
queue<node>q;
void bfs(int bel){
    while(!q.empty()){
        node x=q.front();q.pop();
        int m=x.m,n=x.n,l=x.l;
        ++V[bel];
        if(m>1 && map[m-1][n][l] && !vis[m-1][n][l]){vis[m-1][n][l]=1;q.push((node){m-1,n,l});}
        if(m<M && map[m+1][n][l] && !vis[m+1][n][l]){vis[m+1][n][l]=1;q.push((node){m+1,n,l});}
        if(n>1 && map[m][n-1][l] && !vis[m][n-1][l]){vis[m][n-1][l]=1;q.push((node){m,n-1,l});}
        if(n<N && map[m][n+1][l] && !vis[m][n+1][l]){vis[m][n+1][l]=1;q.push((node){m,n+1,l});}
        if(l>1 && map[m][n][l-1] && !vis[m][n][l-1]){vis[m][n][l-1]=1;q.push((node){m,n,l-1});} 
        if(l<L && map[m][n][l+1] && !vis[m][n][l+1]){vis[m][n][l+1]=1;q.push((node){m,n,l+1});}
    }
}
int main(){
    scanf("%d%d%d%d",&M,&N,&L,&T);
    for(int k=1;k<=L;++k)
    for(int i=1;i<=M;++i)
    for(int j=1;j<=N;++j)
        scanf("%d",&map[i][j][k]);
    for(int k=1;k<=L;++k)
    for(int i=1;i<=M;++i)
    for(int j=1;j<=N;++j)
        if(map[i][j][k] && !vis[i][j][k]){
            vis[i][j][k]=1;
            q.push((node){i,j,k});
            bfs(++cnt);
        }
    for(int i=1;i<=cnt;++i)
    if(V[i]>=T)sum+=V[i];
    printf("%d",sum);
}
View Code
 
7-14 垃圾箱分布
 

大家倒垃圾的时候,都希望垃圾箱距离自己比较近,但是谁都不愿意守着垃圾箱住。所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。

现给定一个居民区的地图,以及若干垃圾箱的候选地点,请你推荐最合适的地点。如果解不唯一,则输出到所有居民点的平均距离最短的那个解。如果这样的解还是不唯一,则输出编号最小的地点。

输入格式:

输入第一行给出4个正整数:N(≤)是居民点的个数;M(≤)是垃圾箱候选地点的个数;K(≤)是居民点和垃圾箱候选地点之间的道路的条数;DS​​是居民点与垃圾箱之间不能超过的最大距离。所有的居民点从1到N编号,所有的垃圾箱候选地点从1到GM编号。

随后K行,每行按下列格式描述一条道路:

P1 P2 Dist
 

其中P1P2是道路两端点的编号,端点可以是居民点,也可以是垃圾箱候选点。Dist是道路的长度,是一个正整数。

输出格式:

首先在第一行输出最佳候选地点的编号。然后在第二行输出该地点到所有居民点的最小距离和平均距离。数字间以空格分隔,保留小数点后1位。如果解不存在,则输出No Solution

输入样例1:

4 3 11 5
1 2 2
1 4 2
1 G1 4
1 G2 3
2 3 2
2 G2 1
3 4 2
3 G3 2
4 G1 3
G2 G1 1
G3 G2 2
 

输出样例1:

G1
2.0 3.3
 

输入样例2:

2 1 2 10
1 G1 9 2 G1 20 
 

输出样例2:

No Solution


建好图之后从每个候选点出发跑一遍最短路就可以了
为了这个题复习了最短路
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
const int N=1019;
const int M=10109;
using namespace std;
int n,m,K,DS,ans;
double ave,maxans;
int p[N],cnt;
struct edge{int to,nex,val;}e[M<<1];
void add(int u,int v,int val){
    e[++cnt]=(edge){v,p[u],val};
    p[u]=cnt; 
}
int dis[N];
struct node{int id,dis;};
bool operator <(node x,node y){return x.dis>y.dis;}
priority_queue<node>q;
inline void dijkstra(int s)
{
    memset(dis,0x3f,sizeof(dis));dis[s]=0;    
    while(!q.empty())q.pop();
    q.push((node){s,0});
    while(!q.empty())
    {
      node cur=q.top();q.pop();
      if(cur.dis!=dis[cur.id])continue;
      int u=cur.id;
      for(int k=p[u];k;k=e[k].nex)
      {
        int v=e[k].to;
        if(dis[v]>dis[u]+e[k].val)
        {
            dis[v]=dis[u]+e[k].val;
            q.push((node){v,dis[v]});
        } 
      }
    }
}
char readnum[10];
void qread(int* x){
    scanf("%s",readnum);
    int poi=0; 
    if(readnum[0]=='G')++poi;
    int num=0;
    while(*(readnum+poi)){
        num=num*10+*(readnum+poi)-'0';
        ++poi;
    }
    if(readnum[0]=='G')num+=n;
    *x=num;
}
int main(){
    scanf("%d%d",&n,&m);
    scanf("%d%d",&K,&DS); 
    for(int i=1;i<=K;++i){
        int u,v,w;
        qread(&u);qread(&v);
        scanf("%d",&w);
//        printf("%d %d %d\n",u,v,w);
        add(u,v,w);
        add(v,u,w);
    }
    for(int s=n+1;s<=n+m;++s){
        dijkstra(s);
        bool flag=1;
        for(int i=1;i<=n&&flag;++i){
            if(dis[i]>DS)flag=0;
        }
        if(!flag)continue;
        
        int temp=dis[0];
        double sum=0;
        for(int i=1;i<=n;++i){
            temp=min(temp,dis[i]);
            sum+=dis[i];
        }
        if(temp>maxans || (temp==maxans && (sum/n)<ave) )
            ans=s,maxans=temp,ave=sum/n;
//        printf("%.1f %.1f\n",maxans,ave);
    }
    if(!ans)printf("No Solution");
    else printf("G%d\n%.1f %.1f",ans-n,maxans,ave);
    return 0;
} 
View Code
 
7-15 迎风一刀斩
 

迎着一面矩形的大旗一刀斩下,如果你的刀够快的话,这笔直一刀可以切出两块多边形的残片。反过来说,如果有人拿着两块残片来吹牛,说这是自己迎风一刀斩落的,你能检查一下这是不是真的吗?

注意摆在你面前的两个多边形可不一定是端端正正摆好的,它们可能被平移、被旋转(逆时针90度、180度、或270度),或者被(镜像)翻面。

这里假设原始大旗的四边都与坐标轴是平行的。

输入格式:

输入第一行给出一个正整数N(≤),随后给出N对多边形。每个多边形按下列格式给出:

x1​​

其中k(2)是多边形顶点个数;((0)是顶点坐标,按照顺时针或逆时针的顺序给出。

注意:题目保证没有多余顶点。即每个多边形的顶点都是不重复的,任意3个相邻顶点不共线。

输出格式:

对每一对多边形,输出YES或者NO

输入样例:

8
3 0 0 1 0 1 1
3 0 0 1 1 0 1
3 0 0 1 0 1 1
3 0 0 1 1 0 2
4 0 4 1 4 1 0 0 0
4 4 0 4 1 0 1 0 0
3 0 0 1 1 0 1
4 2 3 1 4 1 7 2 7
5 10 10 10 12 12 12 14 11 14 10
3 28 35 29 35 29 37
3 7 9 8 11 8 9
5 87 26 92 26 92 23 90 22 87 22
5 0 0 2 0 1 1 1 2 0 2
4 0 0 1 1 2 1 2 0
4 0 0 0 1 1 1 2 0
4 0 0 0 1 1 1 2 0
 

输出样例:

YES
NO
YES
YES
YES
YES
NO
YES
 


这个题没肝出来。。。留坑

猜你喜欢

转载自www.cnblogs.com/wypx/p/12199147.html