zoukankan      html  css  js  c++  java
  • 2014-10-28 NOIP模拟赛

    Porble 1时间与空间之旅(tstrip.*)

    题目描述

    公元22××年,宇宙中最普遍的交通工具是spaceship。spaceship的出现使得星系之间的联系变得更为紧密,所以spaceship船长也成了最热门的职业之一。当然,要成为一名出色的船长,必须通过严格的考核,例如下面是最简单的问题中的一个。

    用1~n的整数给n个星系标号,目前你在标号为1的星系,你需要送快递到标号为n的星系,星系之间由于存在陨石带,并不是都可以直连的。同时,由于超时空隧道的存在,在某些星系间飞行会出现时间静止甚至倒流,飞行时间为0或为负数。另外,由星系i到星系j的时间和由星系j到星系i的时间不一定是相同的。

    在寄出日期之前收到快递被认为是不允许的,所以每部spaceship上都有一个速度调节装置,可以调节飞行的时间。简单来说其功能就是让所有两个星系间的飞行时间(如果可以直达)都增加或减少相同的整数值,你的任务就是调整速度调节器,找出一条用最短时间完成任务的路径,并且保证这个最短时间的值大于或等于0。

    输入格式

    输入文件包含多组数据,第1个数为T,表示数据的数量。

    对于每一组数据,输入第1行为两个正整数N(2≤N≤100),E(1≤E≤N*(N-1)/2),为星系的个数和星系间飞行的路线数。然后E行,每行三个整数i,j和t(1≤i,j≤N,i≠j,-100000≤t≤100000),表示由星系i到星系j飞行的时间为t。由i到j最多只会有一条飞行线路。

    输出格式

    输出文件共T行,每组数据输出一行;

    如果可以通过调节速度调节器完成任务,则输出一个非负整数,表示由星系1到星系N的最短时间。

    如果不能由星系1到达星系N,则输出-1。

    输入样例

    1

    4 5

    1 2 1

    1 3 1

    2 3 -3

    3 1 1

    3 4 1

    输出样例

    2

    样例说明

    输入样例如图所示,其中节点标号表示相应星系,节点间数字表示所需时间。

    如果设置速度控制器的值为0,则有如下路径:1→2→3→1→2→……→3→4,使得投递的时间为负无穷大,显然是不符合要求的,所以应该把速度控制器的值设为1,相当于每个时间值加1,得到的最短路径为1→2→3→4,所需时间为2+(-2)+2=2。

    /*
        二分需要改变的值,判断该值是否可行
        由于要求最短的方案,所以这个值越小越好,满足单调性,可以二分答案,判断条件就是是否存在负环,用spfa
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<stack>
    using namespace std;
    #define maxn 110
    int n,m,dis[maxn],num,head[maxn],T,num2,head2[maxn],ans,t[maxn];
    bool m1[maxn],m2[maxn],mark[maxn],vis[maxn];
    struct node{
        int to,pre,v;
    }e[maxn*maxn/2],e2[maxn*maxn/2];
    void Insert(int from,int to,int v){
        e[++num].to=to;
        e[num].v=v;
        e[num].pre=head[from];
        head[from]=num;
        
        e2[++num2].to=from;
        e2[num2].v=v;
        e2[num2].pre=head2[to];
        head2[to]=num2;
    }
    void dfs1(int now){
        m1[now]=1;
        for(int i=head[now];i;i=e[i].pre){
            int to=e[i].to;
            if(!m1[to])dfs1(to);
        }
    }
    void dfs2(int now){
        m2[now]=1;
        for(int i=head2[now];i;i=e2[i].pre){
            int to=e2[i].to;
            if(!m2[to])dfs2(to);
        }
    }
    bool spfa(int x){
        memset(vis,0,sizeof(vis));
        memset(dis,127/3,sizeof(dis));
        memset(t,0,sizeof(t));
        stack<int>q;
        vis[1]=1;dis[1]=0;t[1]=1;q.push(1);
        while(!q.empty()){
            int now=q.top();q.pop();vis[now]=0;
            for(int i=head[now];i;i=e[i].pre){
                int to=e[i].to;
                if(!mark[to])continue;
                if(dis[to]>dis[now]+e[i].v+x){
                    dis[to]=dis[now]+e[i].v+x;
                    if(!vis[to]){
                        vis[to]=1;
                        t[to]++;
                        if(t[to]>n)return 0;
                        q.push(to);
                    }
                }
            }
        }
        if(dis[n]<0)return 0;
        return 1;
    }
    int main(){
        freopen("tstrip.in","r",stdin);
        freopen("tstrip.out","w",stdout);
        //freopen("Cola.txt","r",stdin);
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            num=0;num2=0;
            memset(head,0,sizeof(head));
            memset(e,0,sizeof(e));
            memset(head2,0,sizeof(head2));
            memset(e2,0,sizeof(e2));
            memset(vis,0,sizeof(vis));
            memset(m1,0,sizeof(m1));
            memset(m2,0,sizeof(m2));
            int x,y,z;
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&x,&y,&z);
                Insert(x,y,z);
            }
            dfs1(1);
            if(!m1[n]){
                printf("-1
    ");
                continue;
            }
            dfs2(n);
            for(int i=1;i<=n;i++)mark[i]=m1[i]&m2[i];
            int l=-100000,r=100000;
            while(l<=r){
                int mid=(l+r)>>1;
                if(spfa(mid)){
                    ans=dis[n];
                    r=mid-1;
                }
                else l=mid+1;
            }
            printf("%d
    ",ans);
        }
    }
    100分 spfa判负环+二分答案

    Problem 2 狐狸的谜语(puzzle.*)

    题目描述

    话说某一个月黑风高的晚上,一只褐色的狐狸快速地跳过了一只懒狗,并留下一个字符串“032089”和一个数字5。

    这其中一定隐含了某些秘密!酷爱思考的你马上发现,这个字符串可以写成:“03+2+0*89”,结果为5。这是一个非常有趣的问题!

    现在给出一个长度为N的数字字符串和一个数字T,要求插入最少的加号或者乘号,使得数字字符串的运算结果为T。运算符*号优先级高于+号,运算数可以有任意个前导0。

    榆入格式

    输入不超过5组数据,每组数据两行。

    每组数据的第1行为长度为N,只包含0~9的数字字符串,第2行为一个数字T。

    输入T<0表示输入结束。

    输出格式

    输出一个数字单独占一行,表示最少需要添加的运算符(+号或*号)数,无解输出-1。

    输入样例

    032089

    5

    333

    9

    00

    -1

    输出样例

    3

    2

    数据范围

    对于30%的数据,有1≤N≤10,0≤T≤50。

    对于50%的数据,有1≤N≤15,0≤T≤200。

    对于全部的数据,有1≤N≤20,0≤T≤200。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int t,num[22][22],len,w[22],op[22];
    int a[22],ans,cnt;
    bool flag;
    char ch[22];
    bool check(){
        cnt=0;
        memset(w,0,sizeof(w));
        int s=1,d=1;
        for(int i=1;i<len;i++){
            if(a[i]==0)d++;
            else {
                cnt=cnt+1;
                w[cnt]=num[s][d];
                op[cnt]=a[i];
                s=d=i+1;
            }
        }
        w[++cnt]=num[s][d];
        for(int i=1;i<cnt;i++){
            if(op[i]==2){
                w[i+1]*=w[i];
                w[i]=0;
            }
        }
        long long sum=0;
        for(int i=1;i<=cnt;i++)sum+=w[i];
        if(sum==t)return 1;
        return 0;
    }
    void dfs(int now,int sum){
        if(sum>ans)return;
        if(now==len){
            if(check())
                flag=1,ans=min(ans,sum);
            return;
        }
        a[now]=1;
        dfs(now+1,sum+1);
        a[now]=2;
        dfs(now+1,sum+1);
        a[now]=0;
        dfs(now+1,sum);
    }
    int main(){
        //freopen("Cola.txt","r",stdin);
        freopen("puzzle.in","r",stdin);
        freopen("puzzle.out","w",stdout);
        while(1){
            flag=0;
            ans=100;
            memset(num,0,sizeof(num));
            memset(a,0,sizeof(a));
            scanf("%s%d",ch+1,&t);
            if(t==-1)return 0;
            len=strlen(ch+1);
            for(int i=1;i<=len;i++)num[i][i]=ch[i]-'0';
            for(int i=1;i<=len;i++)
                for(int j=i+1;j<=len;j++)
                    num[i][j]=num[i][j-1]*10+num[j][j];
            dfs(1,0);
            if(!flag){
                printf("-1
    ");
                continue;
            }
            printf("%d
    ",ans);
        }
    }
    30分 暴力
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    char a[25];
    int len,t,deep,v[25][25];
    bool flag,b[25];
    void pre(){
        for(int i=len;i;i--)
            if(a[i]=='0'){
                while(i--)b[i]=0;
                break;
            }
            else b[i]=1;
        for(int i=1;i<=len;i++)
            for(int j=i;j<=len;j++){
                v[i][j]=v[i][j-1]*10+a[j]-'0';
                v[i][j]=min(v[i][j],t+1);
            }
    }
    void dfs(int x,int k,int last,int mul,int sum){
        if(sum>t||flag||k>deep)return;
        if(x==len){
            if(sum+mul*v[last+1][len]==t)flag=1;
            return;
        }
        if(b[x-1]&&sum+mul>t)return;
        dfs(x+1,k+1,x,1,sum+mul*(v[last+1][x]));
        dfs(x+1,k+1,x,mul*(v[last+1][x]),sum);
        dfs(x+1,k,last,mul,sum);
    }
    void solve(){
        pre();
        int ans=-1;
        int l=0,r=len-1;
        while(l<=r){
            deep=(l+r)>>1;
            flag=0;
            dfs(1,0,0,1,0);
            if(flag)ans=deep,r=deep-1;
            else l=deep+1;
        }
        printf("%d
    ",ans);
    }
    int main(){
        freopen("puzzle.in","r",stdin);
        freopen("puzzle.out","w",stdout);
        while(scanf("%s%d",a+1,&t)){
            if(t==-1)return 0;
            len=strlen(a+1);
            solve();
        }
        return 0;
    }
    100分 二分+迭代加深搜索

    Problem 3花园的守护之神(greendam.*)

    题目描述

    看着正在被上古神兽们摧残的花园,花园的守护之神――小Bug同学泪流满面。然而,FZOI不相信眼泪,小bug与神兽们的战争将进行到底!

    通过google,小Bug得知,神兽们来自遥远的戈壁。为了扭转战局,小Bug决定拖延神兽增援的速度。从戈壁到达花园的路径错综复杂,由若干段双向的小路组成。神兽们通过每段小路都需要一段时间。小Bug可以通过向其中的一些小路投掷小xie来拖延神兽。她可以向任意小路投掷小Xie,而且可以在同一段小路上投掷多只小xie。每只小Xie可以拖延神兽一个单位的时间。即神兽通过整段路程的总时间,等于没有小xie时他们通过同样路径的时间加上路上经过的所有小路上的小xie数目总和。

    神兽们是很聪明的。他们会在出发前侦查到每一段小路上的小Xie数目,然后选择总时间最短的路径。小Bug现在很想知道最少需要多少只小Xie,才能使得神兽从戈壁来到花园的时间变长。作为花园中可爱的花朵,你能帮助她吗?

    输入格式

    第1行包括一个整数N,表示地图中路点的个数;一个整数M,表示小路个数;以及整数S和T,分别表示戈壁和花园的路点编号。N个路点分别被编号为自然数1~N。

    以下M行,每行三个整数A、B和C,表示路点A和B之间有一条小路相连,且通过它需要的时间为C。

    输入数据保证两路点间最多只有一条小路相连,且戈壁和花园的路点是连通的。

    输出格式

    一个整数,表示使S到T之间最短路增长所需要的最少的小xie的数目。

    输入样例

    5 5 1 5

    1 2 1

    2 3 3

    1 4 2

    4 3 2

    5 1

    输出样例

    1

    数据范围

    对于30%的数据,满足N≤10,M≤50。

    对于50%的数据,满足N≤200,M≤10000。

    对于全部的数据,满足N≤1000,M≤499500,0<C≤1000000。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define maxn 1010
    using namespace std;
    int n,m,num,head[maxn],S,T,dis[maxn],f[maxn],mx,sum,falg;
    struct node{
        int v,t,pre,x;
    }e[maxn*maxn];
    queue<int>q;
    int init(){
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    }
    void Add(int from,int to,int dis){
        e[num].v=to;
        e[num].t=dis;
        e[num].pre=head[from];
        head[from]=num++;
    }
    int SPFA(){
        while(!q.empty())q.pop();
        memset(f,0,sizeof(f));
        memset(dis,127/3,sizeof(dis));
        dis[S]=0;f[S]=1;
        q.push(S);
        while(!q.empty()){
            int k=q.front();
            q.pop();f[k]=0;
            for(int i=head[k];i!=-1;i=e[i].pre){
                int v=e[i].v;
                if(dis[v]>dis[k]+e[i].t+e[i].x){
                    dis[v]=dis[k]+e[i].t+e[i].x;
                    if(f[v]==0){
                        f[v]=1;q.push(v);
                    }
                }
            }
        }
        return dis[T];
    }
    void Dfs(int now,int s){
        if(s==sum||now==num){
            if(SPFA()>mx)falg=1;
            return;
        }
        e[now].x++;e[now^1].x++;
        Dfs(now+2,s+1);if(falg)return;
        e[now].x--;e[now^1].x--;
        Dfs(now+2,s);if(falg)return;
    }
    int main()
    {
        freopen("greendam.in","r",stdin);
        freopen("greendam.out","w",stdout);
        n=init();m=init();S=init();T=init();
        int u,v,t;memset(head,-1,sizeof(head));
        for(int i=1;i<=m;i++){
            u=init();v=init();t=init();
            Add(u,v,t);Add(v,u,t);
        }
        mx=SPFA();
        for(sum=0;sum<=m;sum++){
            Dfs(0,0);
            if(falg)break;
        }
        printf("%d
    ",sum);
        return 0;
    }
    30分 暴力
  • 相关阅读:
    Android之dialog
    android上下文菜单(ContextMenu)
    Android中Handler的使用2
    Intent 各种跳转 .
    Android之Adapter用法总结
    android之Menu 实例与详解
    android学习之FrameLayout
    Andriod: 在xml布局中使用自定义属性
    你软考了吗?
    菜鸟从零学习数据库(三)——存储过程
  • 原文地址:https://www.cnblogs.com/thmyl/p/7492996.html
Copyright © 2011-2022 走看看