NOI2016江苏省选Day2T1 详解

来源:互联网 发布:linux axel 编辑:程序博客网 时间:2024/04/26 00:18

JSTSC-Day2T1: Airport 解题报告

【问题描述(大意)】

         JSOI王国有n个机场,m条直达航班。每两个机场之间都有一个固定的飞行时间。由于流量控制,气候,地形等因素,从i到j的飞行时间与从j到i的飞行时间不一定相等。飞机每降落在某一机场,都需要例行检查,维护,加油。在第i座机场维护的时间为pi。

         作为JSOI航空公司的金牌客户,JYY发现JSOI航空公司并没有用m架飞机执行这m条航班。因为JSOI航空公司可以开辟一些临时航班,让一些飞机先后执行多条航班任务。现在给定m条航班的起飞地点,降落地点和起飞时间,JYY希望算出至少需要几架飞机才能完成航班任务。

 

【输入数据】

第一行:两个正整数n和m;

第二行:n个非负整数,其中第i个数表示在第i座机场维护的时间;

下面n行每行n个非负整数,其中第i行第j个表示从第i座机场飞到第j座机场所需的时间,输入数据保证第i行第i个为0;

下面m行每行3个整数,分别为每条航线的起飞机场编号,降落机场编号和起飞时间;

 

【输出数据】

         仅一行,表示完成所有航班所需的最少飞机数

 

【样例输入1(自编,仅供参考)】

3 3

100 1 1

0 1 2

4 0 3

2 1 0

2 3 1

3 1 2

2 1 7

 

【样例输出1】

         2

 

【样例输入2(自编,仅供参考)】

3 3

100 1 1

0 1 2

4 0 3

2 1 0

2 3 1

3 1 2

2 1 6

【样例输出2】

         3

 

【样例说明】

         对于第一组数据,在1时刻用一架飞机执行第一条航线。在2时刻用一架飞机执行第二条航线。第一架飞机执行完航线后,开辟一条临时航线从机场3到机场2,在7时刻再用第一家飞机执行第三条航线。共需要两架飞机。

         对于第二组数据,第一架飞机执行完航线后,要在7时刻才能开始执行第三条航线。而第三条航线要在6时刻执行,所以只能用三架飞机,每架执行一条航线。

 

【数据规模】

对于30%的数据,n, m≤10;

对于100%的数据,n, m≤500;

 

【算法分析】

         这题30%的数据并不好骗,还不如直接想满分算法。(/(o)/~~

         一个简单易想的技巧是把在每个机场维护的时间加到以此机场终点的边权上。因为如果想让飞机继续飞行,这个维护时间是省不了的。这样可以算出每趟航班所需的时间。

         然后跑一遍Floyd求每两点之间的最短路径。[O(n3)的效率并不知道为什么不会炸。。。]

         m条航线抽象成m个点。这样对于航线i和航线j,如果执行完航线i之后来得及再去执行航线j,就在第i个点和第j个点之间连一条有向边<i,j>

         这样就将问题转化成了一个图的最小链覆盖问题。我们可以这样做:如果执行完第i个任务后来得及去执行第j个任务,就在节点i和节点j之间连一条边。如果最初用n架飞机分别执行这n个任务,那么挑中一条边就可以省一架飞机。于是问题转化为了二分图的最大匹配。

         当然,可以用网络流解决。但是用匈牙利算法更简洁更快。这样整个程序的时间复杂度是Floyd的复杂度O(n3),因为n500,所以能过。

 

【参考程序】

#include<cstdio>

#include<iostream>

#include<cstring>

#include<algorithm>

usingnamespace std;

 

structnode

{

         int start;

         int end;

         int    time;

         int need;

}route[501];

 

boolcompare(node x,node y)

{

         return x.time<y.time;

}

 

int n,m;

intga[501][501];

intp[501];

booldata[501][501];

boolstate[501];

intresult[501];

 

boolfind(int num)

{

         int i;

         for (i=1;i<=n;i++)

         {

                   if (data[num][i] &&!state[i])

                   {

                            state[i]=true;

                            if (result[i]==0 ||find(i))

                            {

                                     result[i]=num;

                                     returntrue;

                            }

                   }

         }

         return false;

}

 

int main()

{

         freopen("airport.in","r",stdin);

         freopen("airport.out","w",stdout);

         scanf("%d%d",&n,&m);

         int i,j,k;    

         for (i=1;i<=n;i++)scanf("%d",&p[i]);

         for (i=1;i<=n;i++)

                   for (j=1;j<=n;j++)

                   {

                            scanf("%d",&ga[i][j]);

                            ga[i][j]+=p[j];

                   }

         for (i=1;i<=m;i++)

         {

                   scanf("%d%d%d",&route[i].start,&route[i].end,&route[i].time);

                   route[i].need=ga[route[i].start][route[i].end];

         }

         for (k=1;k<=n;k++)

                   for (i=1;i<=n;i++)

                            for(j=1;j<=n;j++)

                                     if (i!=j&& i!=k && j!=k)

                                     {

                                               if(ga[i][k]+ga[k][j]<ga[i][j]) ga[i][j]=ga[i][k]+ga[k][j];

                                     }

         sort(route+1,route+m+1,compare);

         memset(data,false,sizeof(data));

         for (i=1;i<=m-1;i++)

                   for (j=i+1;j<=m;j++)

                            if(route[i].time+route[i].need+ga[route[i].end][route[j].start]<=route[j].time)

                                     data[i][j]=true;

         int ans=0;

         for (i=1;i<=n;i++)

         {

                   memset(state,false,sizeof(state));

                  if(find(i)) ans++;

         }

         ans=m-ans;

         printf("%d",ans);

         return 0;

}

1 0
原创粉丝点击