您的位置:首页 > 其它

【2015-2016 ACM-ICPC Pacific Northwest Regional Contest (Div 1)A】【floyd 最小路径覆盖】最少飞机数满足所有航班要求

2015-12-03 19:48 579 查看
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=500+5,M=0,Z=1e9+7,ms63=1061109567;
int n,m;
int p
;
int t

,f

;
pair<int,int>a
,b
;
int match
;
bool vis
;
vector<int>w
;
void floyd()
{
MC(f,t);
for(int k=1;k<=n;++k)
{
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
gmin(f[i][j],f[i][k]+f[k][j]);
}
}
}
}
int find(int x)
{
vis[x]=1;
for(int i=w[x].size()-1;~i;--i)
{
int y=w[x][i];
if(match[y]==-1)
{
match[y]=x;
return 1;
}
}
for(int i=w[x].size()-1;~i;--i)
{
int y=w[x][i];
if(!vis[match[y]]&&find(match[y]))
{
match[y]=x;
return 1;
}
}
return 0;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;++i)scanf("%d",&p[i]);
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
scanf("%d",&t[i][j]);
if(i!=j)t[i][j]+=p[j];
}
}
floyd();
for(int i=1;i<=m;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[i]=MP(x,z);
b[i]=MP(y,z+t[x][y]);
}
for(int i=1;i<=m;++i)
{
w[i].clear();
for(int j=1;j<=m;++j)if(i!=j&&b[i].second+f[b[i].first][a[j].first]<=a[j].second)w[i].push_back(j);
}
int ans=0;
MS(match,-1);
for(int i=1;i<=m;++i)
{
MS(vis,0);
if(find(i))++ans;
}
printf("%d\n",m-ans);
}
return 0;
}
/*
【trick&&吐槽】
1,连边的基准是状态,而不是按照机场。
2,匹配的时候一定要防止自己连自己。
3,不同机场之间,能否达到是要用floyd之后的时间。

【题意】
有n(1<=n<=500)个机场。
每两个机场之间有一个抵达时间,i->j的时间被我们记录在a[i][j]中。
同时,如果飞机还要再飞,那到达的机场i还要对飞机做检修,花费时间为p[i];

记下来还有m(1<=m<=500)条航线,
对于第i条航线,有si,fi,ti,表示我们从需要有一架飞机,恰好于时刻ti出发,si直飞到fi。
问你这个公司至少要提供多少架飞机。

【类型】
floyd 最小路径覆盖

【分析】
这道题,我们有m条航线。{si,fi,ti}表示于时刻ti出发,从si到fi的一条航线。可以被标记为一个点。
显然,我们最多只会需要m架飞机。

每个点被自然分配成了2个点,起点和终点,都附带一个事件属性。
如果A的终点和B的起点,可以在时间内相通,那么我们就可以减少一架飞机。
于是,只要floyd后最小路径覆盖就可以解决这道题。

问题来了——
1,floyd可以求出从x到y的时间,因为我们还要保留直达时间,所以,floyd矩阵需要额外算。
我们要把所有抵达点的维修时间算上,这样它才可以继续起飞。
2,最小路径覆盖,我们需要确定什么样的两个点之间可以连边。
什么样的两个点之间可以连边呢?点A的终点时间+(A到B的时间)<=点B的起点时间的时候。

这道题就这样做完啦。

【时间复杂度&&优化】
O(n^3)

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐