NOIP模拟2

期望得分:100+100+100=300

实际得分:70+40+20=130

T1 [SCOI2007]kshort弱化版

Description

  有n个城市和m条单向道路,城市编号为1~n。每条道路连接两个不同的城市,且任意两条道路要么起点不同要么终点不同,因此n和m满足m<=n(n-1)。给定两个城市a和b,可以给a到b的所有简单路(所有城市最多经过一次,包括起点和终点)排序:先按长度从小到大排序,长度相同时按照字典序从小到大排序。你的任务是求出a到b的第k短路。

Input

输入第一行包含五个正整数n, m, k, a, b。以下m行每行三个整数u, v, l,表示从城市u到城市v有一条长度为l的单向道路。100%的数据满足:2<=n<=50, 1<=k<=200

Output

  如果a到b的简单路不足k条,输出No,否则输出第k短路:从城市a开始依次输出每个到达的城市,直到城市b,中间用减号"-"分割。

基本思路:A*跑k短路

错解:重载运算符时比较字典序,直接输出第k短

错因:

正解:记录所有长度<=第k短长度的路径,取第k条

记录路径的时候,定义vector<结构体>,直接sort

vector是从0开始的!!!!

#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 51
using namespace std;
int n,m,k,a,b,sum;
short front[N],nxt[N*N],to[N*N],tot;
short front2[N],nxt2[N*N],to2[N*N],tot2;
int val[N*N],val2[N*N],dis[N];
queue<int>q;
struct node
{
    int num,dis2;
    long long go;
    short cnt,road[N];
    bool operator < (node p) const
    {
        return dis2+dis[num]>p.dis2+dis[p.num];
    }
}cur,nt;
vector<node>ans;
priority_queue<node>q2;
bool vis[N];
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
}
void add(int u,int v,int w)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
    to2[++tot2]=u; nxt2[tot2]=front2[v]; front2[v]=tot2; val2[tot2]=w;
}
void spfa()
{
    memset(dis,63,sizeof(dis));
    dis[b]=0; vis[b]=true; q.push(b);
    int now;
    while(!q.empty())
    {
        now=q.front(); q.pop(); vis[now]=false;
        for(int i=front[now];i;i=nxt[i])
            if(dis[to[i]]>dis[now]+val[i])
            {
                dis[to[i]]=dis[now]+val[i];
                if(!vis[to[i]])
                {
                    vis[to[i]]=true;
                    q.push(to[i]);
                }
            }
    }
}
bool have(long long x,int y)
{
    if(x&(1LL<<y)) return true;
    return false;
}
bool cmp(node h,node g)
{
    if(h.dis2!=g.dis2) return h.dis2<g.dis2;
    for(int i=1;i<=min(h.cnt,g.cnt);i++)
        if(h.road[i]!=g.road[i]) return h.road[i]<g.road[i];
    return h.cnt<g.cnt;
}
void solve()
{
    if(dis[a]>2e9)
    {
        printf("No");
        return;
    }
    if(a==b) k++;
    cur.cnt=1;
    cur.dis2=0;
    cur.go=1LL<<a;
    cur.num=cur.road[1]=a;
    q2.push(cur);
    while(!q2.empty())
    {
        cur=q2.top(); q2.pop();
        if(cur.num==b)
        {
            sum++;
            ans.push_back(cur);
            if(sum>k && cur.dis2>ans[k-1].dis2) break;
        }
        for(int i=front2[cur.num];i;i=nxt2[i])
            if(!have(cur.go,to2[i]))
            {
                nt.cnt=cur.cnt+1;
                nt.dis2=cur.dis2+val2[i];
                nt.go=cur.go|(1LL<<to2[i]);
                nt.num=to2[i];
                for(int j=1;j<=cur.cnt;j++) nt.road[j]=cur.road[j];
                nt.road[nt.cnt]=to2[i];
                q2.push(nt);
            }
    }
    if(ans.size()>=k)
    {
        sort(ans.begin(),ans.end(),cmp);
        printf("%d",a);
        for(int i=2;i<=ans[k-1].cnt;i++) printf("-%d",ans[k-1].road[i]);
        return;
    }
    printf("No");
}
int main()
{
    read(n); read(m); read(k); read(a); read(b);
    int u,v,w;
    while(m--)
    {
        read(u); read(v); read(w);
        add(v,u,w);
    }
    spfa();
    solve();
}

T2[ZJOI2007]最大半连通子图

Description

  一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意
两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。若G‘=(V‘,E‘)满足V‘?V,E‘是E中所有跟V‘有关的边,
则称G‘是G的一个导出子图。若G‘是G的导出子图,且G‘半连通,则称G‘为G的半连通子图。若G‘是G所有半连通子图
中包含节点数最多的,则称G‘是G的最大半连通子图。给定一个有向图G,请求出G的最大半连通子图拥有的节点数K
,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出C对X的余数。

Input

  第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述接下来M行,每行两个正整
数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。N ≤1
00000, M ≤1000000;对于100%的数据, X ≤10^8

Output

  应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

tarjan缩环,然后拓扑排序求最长链

注意缩环之后重新构图会出现重边,在拓扑排序里计算方案数时会多算

所以拓扑排序时判断一下是否被同一节点重复更新

错因:没有想到重边,存边的数组大小与点混淆

#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 100001
#define M 1000001
using namespace std;
int mod,tot,cnt;
int front[N],nxt[M],to[M],from[M];
int front2[N],nxt2[M],to2[M],ru[N];
int dp[N][2],maxn,ans;
int dfn[N],low[N],col[N],siz[N],st[N],top;
bool vis[N];
int last[N];
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
}
void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u;
}
void add2(int u,int v)
{
    to2[++tot]=v; nxt2[tot]=front2[u]; front2[u]=tot; ru[v]++;
}
void tarjan(int now)
{
    low[now]=dfn[now]=++tot;
    st[++top]=now;
    vis[now]=true;
    for(int i=front[now];i;i=nxt[i])
    {
        if(!dfn[to[i]])
        {
            tarjan(to[i]);
            low[now]=min(low[now],low[to[i]]);
        }
        else if(vis[to[i]]) low[now]=min(low[now],dfn[to[i]]);
    }
    if(low[now]==dfn[now])
    {
        cnt++;
        while(top && st[top]!=now)
        {
            col[st[top]]=cnt;
            vis[st[top]]=false;
            top--;
        }
        col[now]=cnt;
        vis[now]=false;
        top--;
    }
}
void topsort()
{
    top=0;
    for(int i=1;i<=cnt;i++)
        if(!ru[i])
        {
            st[++top]=i;
            dp[i][0]=siz[i];
            dp[i][1]=1;
        }
    int now;
    while(top)
    {
        now=st[top]; top--;
        for(int i=front2[now];i;i=nxt2[i])
        {
            if(dp[now][0]+siz[to2[i]]>dp[to2[i]][0])
            {
                dp[to2[i]][0]=dp[now][0]+siz[to2[i]];
                dp[to2[i]][1]=dp[now][1];
                last[to2[i]]=now;
            }
            else if(dp[now][0]+siz[to2[i]]==dp[to2[i]][0])
            {
                if(last[to2[i]]==now)
                {
                    ru[to2[i]]--;
                    if(!ru[to2[i]]) st[++top]=to2[i];
                    continue;
                }
                last[to2[i]]=now;
                dp[to2[i]][1]+=dp[now][1];
                dp[to2[i]][1]%=mod;
            }
            ru[to2[i]]--;
            if(!ru[to2[i]]) st[++top]=to2[i];
        }
    }
}
int main()
{
    int n,m;
    read(n); read(m); read(mod);
    int u,v;
    for(int i=1;i<=m;i++)
    {
        read(u); read(v);
        add(u,v);
    }
    tot=0;
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++) siz[col[i]]++;
    tot=0;
    for(int i=1;i<=m;i++)
        if(col[from[i]]!=col[to[i]]) add2(col[from[i]],col[to[i]]);
    topsort();
    for(int i=1;i<=cnt;i++) maxn=max(maxn,dp[i][0]);
    for(int i=1;i<=cnt;i++)
        if(maxn==dp[i][0]) ans+=dp[i][1],ans%=mod;
    printf("%d\n%d",maxn,ans);
}
?

T3[AHOI2006]上学路线route

Description

可可和卡卡家住合肥市的东郊,每天上学他们都要转车多次才能到达市区西端的学校。直到有一天他们两人参加了学校的信息学奥林匹克竞赛小组才发现每天上学的乘车路线不一定是最优的。 可可:“很可能我们在上学的路途上浪费了大量的时间,让我们写一个程序来计算上学需要的最少时间吧!” 合肥市一共设有N个公交车站,不妨将它们编号为1…N的自然数,并认为可可和卡卡家住在1号汽车站附近,而他们学校在N号汽车站。市内有M条直达汽车路线,执行第i条路线的公交车往返于站点pi和qi之间,从起点到终点需要花费的时间为ti。(1<=i<=M, 1<=pi, qi<=N) 两个人坐在电脑前,根据上面的信息很快就编程算出了最优的乘车方案。然而可可忽然有了一个鬼点子,他想趁卡卡不备,在卡卡的输入数据中删去一些路线,从而让卡卡的程序得出的答案大于实际的最短时间。而对于每一条路线i事实上都有一个代价ci:删去路线的ci越大卡卡就越容易发现这个玩笑,可可想知道什么样的删除方案可以达到他的目的而让被删除的公交车路线ci之和最小。 [任务] 编写一个程序: ? 从输入文件中读取合肥市公交路线的信息; ? 计算出实际上可可和卡卡上学需要花费的最少时间; ? 帮助可可设计一个方案,删除输入信息中的一些公交路线,使得删除后从家到学校需要的最少时间变大,而被删除路线的ci和最小;向输出文件输出答案。

Input

输入文件中第一行有两个正整数N和M,分别表示合肥市公交车站和公交汽车路线的个数。以下M行,每行(第i行,总第(i+1)行)用四个正整数描述第i条路线:pi, qi, ti, ci;具体含义见上文描述。

Output

输出文件最多有两行。 第一行中仅有一个整数,表示从可可和卡卡家到学校需要的最短时间。 第二行输出一个整数C,表示Ci之和

思路:找出所有的最短路,重新建图,跑最小割

错因:

确定这条边在最短路上:

正确方法:dis[s,u]+w+dis[v,t]=dis[s,t]

错误方法:从t开始枚举,dis[1,u]+w=dis[1,v],只是计算了1到某个点的最短路

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define N 501
#define M 200001
using namespace std;
int n,m;
int dis[N][N];
int e[M][4];
int src,decc;
int tot=1,front2[N],to2[M<<1],nxt2[M<<1],cap[M<<1],lev[N],cur[N];
bool vis[N];
queue<int>q;
void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); }
}
void add2(int u,int v,int w)
{
    to2[++tot]=v; nxt2[tot]=front2[u]; front2[u]=tot; cap[tot]=w;
    to2[++tot]=u; nxt2[tot]=front2[v]; front2[v]=tot; cap[tot]=0;
}
void build()
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(k!=i && i!=j && k!=j)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    int minn=dis[1][n];
    printf("%d\n",minn);
    for(int i=1;i<=m;i++)
    {
        if(dis[1][e[i][0]]+e[i][2]+dis[e[i][1]][n]==minn)
            add2(e[i][0],e[i][1],e[i][3]);
        if(dis[1][e[i][1]]+e[i][2]+dis[e[i][0]][n]==minn)
            add2(e[i][1],e[i][0],e[i][3]);
    }

}
bool spfa2()
{
    for(int i=1;i<=n;i++) cur[i]=front2[i],lev[i]=-1;
    while(!q.empty()) q.pop();
    lev[1]=0; q.push(1);
    int now;
    while(!q.empty())
    {
        now=q.front();    q.pop();
        for(int i=front2[now];i;i=nxt2[i])
            if(lev[to2[i]]==-1 && cap[i]>0)
            {
                lev[to2[i]]=lev[now]+1;
                if(to2[i]==n) return true;
                q.push(to2[i]);
            }
    }
    return false;
}
int dinic(int now,int flow)
{
    if(now==n) return flow;
    int delta,rest=0;
    for(int & i=cur[now];i;i=nxt2[i])
        if(lev[to2[i]]>lev[now] && cap[i]>0)
        {
            delta=dinic(to2[i],min(cap[i],flow-rest));
            if(delta)
            {
                cap[i]-=delta; cap[i^1]+=delta;
                rest+=delta; if(rest==flow) break;
            }
        }
    if(rest!=flow) lev[now]=-1;
    return rest;
}
int main()
{
    read(n); read(m);
    int u,v,t,c;
    memset(dis,63,sizeof(dis));
    for(int i=1;i<=n;i++) dis[i][i]=0;
    for(int i=1;i<=m;i++)
    {
        read(u); read(v); read(t); read(c);
        e[i][0]=u; e[i][1]=v; e[i][2]=t; e[i][3]=c;
        dis[u][v]=dis[v][u]=min(dis[u][v],t);
    }
    build();
    int ans=0;
    while(spfa2())
    ans+=dinic(1,2e9);
    printf("%d",ans);
}

时间: 2024-10-12 22:01:02

NOIP模拟2的相关文章

NOIP模拟17.8.17

NOIP模拟17.8.17 A 小 G 的字符串文件名 输入文件 输出文件 时间限制 空间限制str.pas/c/cpp str.in str.out 1s 128MB[题目描述]有一天,小 L 给小 G 出了这样一道题:生成一个长度为 n 的.全由小写英文字母构成的字符串,只能使用 k 种字母.要求满足:• 字符串中相邻的两个字母不能相同.• 必须出现恰好 k 种不同的字母.这样的合法字符串可能有很多,小 L 让小 G 输出字典序最小的那个.小 G 太笨啦,不会做这道题,希望你帮帮他.[输入格

[BZOJ入门OJ2092][Noip模拟题]舞会

2092: [Noip模拟题]舞会 Time Limit: 20 Sec  Memory Limit: 256 MB Submit: 9  Solved: 5 [Submit][Status][Web Board] Description 学校举行舞会啦,一共有N个人参加,所有人站成一排,从左开始编号,最左边的人编号为1 ,最右边的为N.每个人跳舞的熟练度我们用一个整数表示,第i个人的熟练度为Ai,每次熟 练度最接近的一对相邻男女会出列跳舞,如果有多对那么最左边的那一对会先出列,请你给 出出列跳

【简单思考】noip模拟赛 NTR酋长

NTR酋长 (ntr.pas/.c/.cpp) 黄巨大终于如愿以偿的进入了czy的后宫中……但是czy很生气……他要在黄巨大走到他面前的必经之路上放上几个NTR酋长来阻挡黄巨大. 众所周知,NTR酋长有一个技能是沟壑(F).它会在地图上产生一条长长的障碍物阻挡人前进.Czy打算在一个n*m的矩形(必经之路?)中放上NTR酋长.NTR酋长要一个一个放下去,而且每放一个都会向四角倾斜的方向放出无限长的沟壑,而已经被沟壑挡住的地方就不能再放NTR酋长了. 请注意:不会出现沟壑的路径挡住另一个沟壑的情况

【noip模拟赛】 射击

这题似乎是什么安阳一中的模拟题,不管了,反正是学长出的noip模拟赛里面的题目.... 射击(shoot.pas/.c/.cpp) 时间限制:1s,内存限制128MB 题目描述: 据史书记载,对越反击战时期,有位中国侦察兵,他的代号叫814.一天他执行狙击任务,他的任务地区是n座恰巧在一条直线上的山.这些山所在直线恰巧为东西走向,山从东到西依次编号为1~n.一天814隐藏在编号为k的山上,每座山上都有1个目标. 814也非常的厉害,任务结束时杀了很多人,可是史书中只记载了两点: 1:814一定攻

NOIP模拟赛

#1[Nescafé 31]杯NOIP模拟赛 t1 题意:n*m的棋盘上从(1,1)走到(n,m),只能向下或向右,一些格子有老鼠,每个老鼠互不相同,当处于与老鼠有重边的格子时,视为看见了这只老鼠,求到终点看到最少的不同老鼠数. 分析:DP 由于求得是看到的不同的老鼠数目,不能直接用过河卒做,因为同一个位置的老鼠可能会统计多次,我们还需要增加一维即方向. f[i,j,0]表示到从上面一个格子走到(i,j)时最少老鼠数,f[i,j,1]表示左边. f[i,j,0]:=min(f[i-1,j,0]+

NOIP模拟 17.8.18

NOIP模拟17.8.18 A.小菜一碟的背包[题目描述]Blice和阿强巴是好朋友但萌萌哒Blice不擅长数学,所以阿强巴给了她一些奶牛做练习阿强巴有 n头奶牛,每头奶牛每天可以产一定量的奶,同时也需要一定量的草作为饲料对于第 i头奶牛来说,它每天可以产 vi升的奶,同时需要 wi千克的草作为饲料现在来自蚯蚓国的九条可怜想借一些奶牛,使借走的这些奶牛每天的总产奶量最大,但九条可怜很穷,每天最多只能提供W千克的草作为饲料,而且她还需要对付跳蚤国的神刀手,所以她把这个问题交给了阿强巴,不不不……阿

NOIP模拟 6.28

NOIP模拟赛6.28 Problem 1 高级打字机(type.cpp/c/pas) [题目描述] 早苗入手了最新的高级打字机.最新款自然有着与以往不同的功能,那就是它具备撤销功能,厉害吧. 请为这种高级打字机设计一个程序,支持如下3种操作: 1.T x:在文章末尾打下一个小写字母x.(type操作) 2.U x:撤销最后的x次修改操作.(Undo操作) (注意Query操作并不算修改操作) 3.Q x:询问当前文章中第x个字母并输出.(Query操作) 文章一开始可以视为空串. [输入格式]

NOIP模拟17.9.21

NOIP模拟17.9.21 1 任务安排manage.in/.out/.cpp1.1 问题描述你有N 个工作,同一时刻只能做一个任务, 其中每个工作有其所需时间, 及完成的Deadline(截止时间), 问要完成所有工作, 最迟要从什么时候开始.你最早可以从时间0 开始工作.1.2 输入格式第一行一个整数N,表示任务数量接下来n 行,每行两个整数,Ti; Si,分别表示该任务的持续时间和截止时间.1.3 输出格式输出一个整数,表示最晚的开始时间,如果不能完成,输出-1.1.4 样例输入43 58

NOIP模拟赛 6.29

2017-6-29 NOIP模拟赛 Problem 1 机器人(robot.cpp/c/pas) [题目描述] 早苗入手了最新的Gundam模型.最新款自然有着与以往不同的功能,那就是它能够自动行走,厉害吧. 早苗的新模型可以按照输入的命令进行移动,命令包括‘E’.‘S’.‘W’.‘N’四种,分别对应东南西北.执行某个命令时,它会向对应方向移动一个单位.作为新型机器人,它可以执行命令串.对于输入的命令串,每一秒它会按命令行动一次.执行完命令串的最后一个命令后,会自动从头开始循环.在0时刻时机器人

NOIP模拟17.9.22

NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥ ??的位置去,但很不幸数轴上有??个区间是禁区,不能进入.青蛙会选择一个长度??,从原点开始每次向右跳长度为??的一段.一路上青蛙会停的位置是0, ??, 2??,…直到跳到了≥ ??的位置,任意一个位置都不能在禁区中.请求出??的最小值,注意??可以是实数.[输入格式]输入文件为susume.in.输入文件的第一行包含两个整数??和??,含义如问题描述中所述.接下来??行,每行描述一个禁区.每行有两个整数