标签:pilot work experienc ural 1888 并查集 floyd
Time Limit: 1000MS | Memory Limit: 65536KB | 64bit IO Format: %I64d & %I64u |
Description
Input
Output
Sample Input
input | output |
---|---|
4 4 1 2 3 1 2 4 3 4 |
2 1 2 2 3 |
3 3 1 2 2 3 1 3 |
-1 |
Source
题意: 有n个航班,p个飞行员,每个航班要两个机长一起飞,一个机长一个副机长,现在每个机长的有一个经验值,并且正机长比副机长的经验值大1,现在不知道每个机长的经验值,只知道每个航班是那两个机长飞的,要求给每个机长规定一个经验值,并且尽量要最小值与最大值之差最大,输出任意一组解,若不存在解输出-1.
思路:在训练赛过程中我的思路是最短路,如果存在可行解并且图是联通的,那么差值的最大值为最短路中的最大值,这个就很好处理了,求一遍floyd再求出mp[i][j]的最大值并记录下起点和终点,起点处的经验值为1,那其他点的经验值为该点到起点的距离+1,这个应该很好理解;如果图是不连通的,那么把其中一个集合内的任意一点s的经验值赋为1使它最小,其他集合选择任意一点s赋为50,使它最大。好,怎样判断时候存在解呢?我当时想到的是带权并查集,这个就可以用并查集来判断是否有解,就和poj 2492 A Bug‘s Life找同性恋的一样。哎,比赛时手抖把并查集的num数组初始化为1了,WA到死=-=
下来后看到网上都是dfs+bfs做的,以后补上。
代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<string> #include<iostream> #include<queue> #include<cmath> #include<map> #include<stack> #include<set> using namespace std; #define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i ) #define REP( i , n ) for ( int i = 0 ; i < n ; ++ i ) #define CLEAR( a , x ) memset ( a , x , sizeof a ) const int INF=0x3f3f3f3f; typedef long long LL; const int maxn = 1000; int mp[maxn][maxn]; int n,p; int father[maxn],num[maxn]; bool ok; vector<int>g[maxn]; int cnt; bool vis[maxn]; int ans[maxn]; void init() { for (int i=0;i<maxn;i++) { father[i]=i; num[i]=0; //这里开始赋的1,作死 } } int find_father(int x) { if (x==father[x]) return x; int t=father[x]; father[x]=find_father(father[x]); num[x]=(num[x]+num[t])%2; return father[x]; } void Union(int a,int b) { int fa=find_father(a); int fb=find_father(b); if (fa==fb) { if ((num[a]+num[b]+2)%2==0) ok=false; return ; } father[fa]=fb; num[fa]=(num[b]-num[a]+1)%2; return ; } void floyd() //floyd求最短路 { for (int k=1;k<=p;k++) { for (int i=1;i<=p;i++) { if (mp[i][k]==INF) continue; for (int j=1;j<=p;j++) { if (mp[k][j]==INF) continue; if (mp[i][j]>mp[i][k]+mp[k][j]) mp[i][j]=mp[i][k]+mp[k][j]; } } } } void ffd() //分离集合 { cnt=0; memset(vis,false,sizeof(vis)); for (int i=0;i<maxn;i++) g[i].clear(); int x; for (int i=1;i<=p;i++) { x=find_father(i); if (!vis[x]) { vis[x]=true; cnt++; } g[x].push_back(i); } } void solve() { ffd(); floyd(); if (cnt==1) //如果只有一个集合就找出最短路中的最长的 { int Max=-1,s,t; for (int i=1;i<=p;i++) { for (int j=1;j<=p;j++) { if (i!=j&&mp[i][j]!=INF&&Max<mp[i][j]) { Max=mp[i][j]; s=i; t=j; } } } mp[s][s]=0; printf("%d\n",mp[s][t]); printf("%d",mp[1][s]+1); for (int i=2;i<=p;i++) printf(" %d",mp[i][s]+1); printf("\n"); return ; } int flag=1; for (int i=1;i<=p;i++) { if (g[i].size()==0) continue; if (flag) //找一个集合赋最小值1 { flag=0; int ss=g[i][0]; ans[ss]=1; for (int j=1;j<g[i].size();j++) ans[g[i][j]]=mp[ss][g[i][j]]+1; } else //其他集合赋最大值50 { int ss=g[i][0]; ans[ss]=50; for (int j=1;j<g[i].size();j++) ans[g[i][j]]=50-mp[ss][g[i][j]]; } } printf("49\n"); printf("%d",ans[1]); for (int i=2;i<=p;i++) printf(" %d",ans[i]); printf("\n"); return ; } int main() { int i,j,a,b; while (~scanf("%d%d",&n,&p)) { init(); ok=true; memset(mp,INF,sizeof(mp)); for (i=0;i<n;i++) { scanf("%d%d",&a,&b); mp[a][b]=mp[b][a]=1; if (!ok) continue; Union(a,b); } if (!ok) { printf("-1\n"); continue; } solve(); } return 0; } /* 12 11 1 2 1 3 3 4 2 4 8 9 8 10 10 11 6 8 7 11 4 5 5 7 5 6 */
版权声明:本文为博主原创文章,未经博主允许不得转载。
Pilot Work Experience (URAL 1888 并查集+floyd)
标签:pilot work experienc ural 1888 并查集 floyd
原文地址:http://blog.csdn.net/u014422052/article/details/47361639