2014 BUPT 新生排位赛08

本文精选了四道算法竞赛题目并提供了详细的解题思路及代码实现,包括凸多边形卡位问题、图上的最小最大权值路径问题、缺失数字查找以及概率DP问题。

A  游戏

链接:http://code.bupt.edu.cn/problem/p/448/

大致题意:给一个凸多边形,求固定一条边水平,存在的能将多边形卡住的方案个数(固定不同的边属于不同方案)。

思路:思路对于每条边如果其与其相邻的两条边所构成的角度存在一个是钝角则此边存在满足方案否则此边不存在方案。有了这个结论再从头到尾扫一下每条边就可以得出方案数了。

感触:一开始没有思路,后来还是听到了旁边人说钝角才恍然大悟,一开始求钝角的方法好复杂用了点积除以模积,后来发现直接点积就可以,哎~~~。

code:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
 
const int MAX_V=1005;;
const int MAX_N=100000;
const int Pi=acos(-1.0);
struct ppp
{
    double x,y;
} P[MAX_V];
int n;
double j(double x1,double y1,double x2,double y2,double x3,double y3)
{
    double X1,X2,Y1,Y2;
    X1=x2-x1;
    Y1=y2-y1;
    X2=x3-x1;
    Y2=y3-y1;
    double jj;
    jj=X1*X2+Y1*Y2;
    return jj;
}
 
int main()
{
    int n,res;
    while(scanf("%d",&n)!=EOF){
        for(int i=1;i<=n;i++) scanf("%lf%lf",&P[i].x,&P[i].y);
        res=0;
        P[0]=P[n];
        P[n+1]=P[1];
        for(int i=1;i<=n-1;i++){
            double j1=j(P[i].x,P[i].y,P[i-1].x,P[i-1].y,P[i+1].x,P[i+1].y);
            double j2=j(P[i+1].x,P[i+1].y,P[i].x,P[i].y,P[i+2].x,P[i+2].y);
            if(j1<0||j2<0) res++;
        }
        double j1=j(P[n].x,P[n].y,P[n-1].x,P[n-1].y,P[1].x,P[1].y);
        double j2=j(P[1].x,P[1].y,P[n].x,P[n].y,P[2].x,P[2].y);
        if(j1<0||j2<0) res++;
        printf("%d\n",res);
    }
    return 0;
}

B 小妹妹送快递

链接:http://code.bupt.edu.cn/problem/p/468/

大致题意:给你一个图,一个起点,一个终点,求两点间的最小最大权值路(就是每条路的权值为各条路权值的最大值,问你最小权值的路)。

思路:我一看题就想到了的改版的spfa,敲了一个,wa了不知道怎么办就去做其他题了,后来想到了神情况就是等于0的时候也得去一个人,当时那感觉真的是太酸爽了,改了一下又wa了,真是没折了去看D题,结果rejudge给A掉了,当时那叫一个开心呀。

code:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF 1000000000
#define eps 1e-6
using namespace std;
 
const int MAX_N=10005;
const int MAX_E=500005;
const int MAX_Q=10000005;
 
int dis[MAX_N],cnt[MAX_N];
bool vis[MAX_N];
int que[MAX_Q];
int h,t,V,M,si,W;
int head[MAX_E];
 
struct edge
{
    int to,cost,next;
} E[MAX_E];
 
void add_edge(int s,int t,int c)
{
    E[si].to=t;
    E[si].cost=c;
    E[si].next=head[s];
    head[s]=si++;
}
void spfa(int s)
{
    for(int i=1;i<=V;i++) dis[i]=INF;
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    dis[s]=0;
    h=t=0;
    que[t++]=s;
    vis[s]=true;
    cnt[s]++;
    while(h!=t){
        int v=que[h++];
        for(int i=head[v];i!=-1;i=E[i].next){
            if(max(E[i].cost,dis[v])<dis[E[i].to]){
                dis[E[i].to]=max(E[i].cost,dis[v]);
                if(!vis[E[i].to]){
                    vis[E[i].to]=true;
                    que[t++]=E[i].to;
                    cnt[E[i].to]++;
                }
            }
        }
        vis[v]=false;
    }
}
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&V,&M);
        memset(head,-1,sizeof(head));
        si=0;
        int s,t,cc;
        for(int i=0;i<M;i++){
            scanf("%d%d%d",&s,&t,&cc);
            add_edge(s,t,cc);
            add_edge(t,s,cc);
        }
        spfa(1);
        if(dis[V]==INF) printf("shimatta!\n");
        else if(V>1&&(dis[V]==0)) printf("1\n");
        else printf("%d\n",dis[V]);
    }
    return 0;
}

C 学姐点名

大致题意:给出N-1个数问1~N个数中那个没出现

思路:对给定的每个N可以用等差数列的求和公式求出来前N个数的和,在输入的时候每次减去输入的数最后剩下的就是待求数。

code:

#include <iostream>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
using namespace std;
 
int main()
{
    int n,t;
    while(~scanf("%d",&n)){
        long long sum=((long long)n)*(n+1)/2;
        for(int i=1;i<n;i++){
            scanf("%d",&t);
            sum-=t;
        }
        printf("%lld\n",sum);
    }
    return 0;
}

D 解码锦标赛

链接:http://code.bupt.edu.cn/problem/p/452/

大致题意:见题目感觉说的很清楚了。

思路:概率dp,dp[i][j]表示j选手通过i轮的概率,递推关系式是dp[i][j]=(dp[i-1][j])*(sigma)(dp[i-1][k]) sigma表示求和,k表j可能的对手,这道题的难处就是找这个k。

第一轮每个人的对手只有一个人,第二轮每个人可能的对手有2个人,第三轮每个人可能的对手有4个人,所以N轮可能的对手就有2^N个,设每论的对手个数为t,再将选手每

个分成一组,经观察发现若(j+t-1)/t是奇数,则j的对手就在他的下一组中否则为上一组,比赛时就观察了一个2结果打成了(j+1)/t就没过掉这题,真是遗憾呀。

code:

#include <iostream>
#include <cstring>
#include <cstdlib>
#include<cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#define INF 1000000000
#define eps  0.001
using namespace std;
 
const int MAX_N=300;
const int MAX_M=10;
 
double dp[MAX_N][MAX_N];
double p[MAX_N][MAX_N];
int N;
int a[10];
int main()
{
    int N,t,nn,n,mm;
    mm=2;
    for(int i=1;i<=10;i++){
        a[i]=mm;
        mm*=2;
    }
    scanf("%d",&N);
    while(N!=0){
        memset(dp,0,sizeof(dp));
        n=1;
        n=a[N];
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%lf",&p[i][j]);
        for(int i=1;i<=n;i+=2){
            dp[1][i]=p[i][i+1];
            dp[1][i+1]=p[i+1][i];
        }
        t=2;
        for(int i=2;i<=N;i++){
            int j=1;
            while(j<=n){
                int mid=(j+t-1)/t;
                if(mid%2){
                    for(int k=mid*t+1;k<=(mid+1)*t;k++){
                        dp[i][j]+=dp[i-1][k]*p[j][k]*dp[i-1][j];
                        dp[i][k]+=dp[i-1][j]*p[k][j]*dp[i-1][k];
                    }
                }
                j++;
                if(((j+t-1)/t)!=mid) j+=t;
            }
            t*=2;
        }
        nn=1;
        for(int i=2;i<=n;i++)   if(dp[N][i]-dp[N][nn]>eps) nn=i;
        printf("%d\n",nn);
        scanf("%d",&N);
    }
    return 0;
}

E 还没做

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值