题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=32568
【思路】
DAG的最小路径覆盖。
将每个人看做一个结点,如果时间允许到达就连边,则问题转化为DAG上的最小路径覆盖问题,即找到最少的路径使得每个点位于一条路径上。
算法:将DAG中的每个结点u拆分成2个为u1,u2,如果DAG中有边uv则连边u1-v2。如果该二分图的最大匹配数为ans,则答案为n-ans。可以这样想:在一条路径中除尾结点外其他结点都有且仅有一个后缀结点,把一个匹配看作成功找到一个后缀结点,则匹配数最大化即为尾结点最小化,即为路径数最小化。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 8 const int maxn = 1000+10; 9 10 bool T[maxn]; 11 int lky[maxn]; 12 vector<int> G[maxn]; 13 14 bool match(int u) { 15 for(int i=0;i<G[u].size();i++) { 16 int v=G[u][i]; 17 if(!T[v]) { 18 T[v]=1; 19 if(!lky[v] || match(lky[v])) { 20 lky[v]=u; 21 return true; 22 } 23 } 24 } 25 return false; 26 } 27 28 int n; 29 int tsta[maxn],tend[maxn],ex[maxn],ey[maxn],sx[maxn],sy[maxn]; 30 31 int dist(int i,int j) { 32 return abs(sx[j]-ex[i])+abs(sy[j]-ey[i]); 33 } 34 35 int main() { 36 int K; 37 scanf("%d",&K); 38 while(K--) { 39 scanf("%d",&n); 40 for(int i=1;i<=n;i++) G[i].clear(); 41 for(int i=1;i<=n;i++) { 42 char s[10]; scanf("%s",s); 43 tsta[i]=((s[0]-'0')*10+(s[1]-'0'))*60+((s[3]-'0')*10+(s[4]-'0')); 44 scanf("%d%d%d%d",&sx[i],&sy[i],&ex[i],&ey[i]); 45 tend[i]=tsta[i]+dist(i,i); 46 } 47 for(int i=1;i<=n;i++) 48 for(int j=1;j<=n;j++) if(i!=j) { 49 if(tend[i]+dist(i,j)+1 <= tsta[j]) 50 G[i].push_back(j); 51 } 52 memset(lky,0,sizeof(lky)); 53 int ans=0; 54 for(int i=1;i<=n;i++) { 55 memset(T,0,sizeof(T)); 56 if(match(i)) ans++; 57 } 58 printf("%d\n",n-ans); 59 } 60 return 0; 61 }