HDU 3991 Harry Potter and the Present II(Floyd+DAG最小路径覆盖)
http://acm.hdu.edu.cn/showproblem.php?pid=3991
题意:
一幅图上有N个点,M条边,边的权值表示通过这条边所需要的时间。有Q个任务,每次任务以Ci,Ti的形式给出Ci表示城市编号,Ti表示任务需要在Ti这个时间点完成.现在你拥有一个人,问至少还需要几个人才能完成所有城市给定时间上的任务。每个人都可以在任何时间点出现在任何城市。
分析:
本题很类似于POJ3216:
http://blog.csdn.net/u013480600/article/details/38711435.
我们把每个任务看成一个点,如果我们完成任务i之后还能在任务j开始之前到达j所在的城市,那么就连一条从i到j的有向边。 我们就得到一个DAG图了。
为了要让人员充分利用,一个人送完一个地方的礼物后,如果他还来的及赶到另外一个地方去送礼,那么明显他应该继续去送礼。这就形成了本DAG图的一条简单路径(即单向路径)。
为了要使人员最少且每个礼物都送到,那么我们就要找出尽量少的简单路径(每条路径不相交)且所有简单路径正好覆盖了DAG图的所有顶点。
那么我们总共需要送礼物的人就是本DAG图的最小路径覆盖数。.
那么本题只需要建立二分图,然后用Q 减去二分图最大匹配数 即是总共需要送礼物的人。(不要忘了减去哈利自己哦)
AC代码:
#include<cstdio> #include<cstring> #include<vector> using namespace std; const int maxn=1000+10; struct Max_Match { int n; vector<int> g[maxn]; bool vis[maxn]; int left[maxn]; void init(int n) { this->n=n; for(int i=1;i<=n;i++) g[i].clear(); memset(left,-1,sizeof(left)); } bool match(int u) { for(int i=0;i<g[u].size();++i) { int v=g[u][i]; if(!vis[v]) { vis[v]=true; if(left[v]==-1 || match(left[v])) { left[v]=u; return true; } } } return false; } int solve() { int ans=0; for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(match(i)) ++ans; } return ans; } }MM; #define INF 1LL<<60 long long dist[110][100]; void floyd(int n) { for(int k=0;k<n;k++) for(int i=0;i<n;i++) for(int j=0;j<n;j++) if(dist[i][k]<INF && dist[k][j]<INF) dist[i][j]=min(dist[i][j], dist[i][k]+dist[k][j]); } struct Node { int p,t; bool link(Node& rhs) { return rhs.t>= t+dist[p][rhs.p]; } }nodes[maxn];//用于保存每个任务 int main() { int T; scanf("%d",&T); for(int kase=1;kase<=T;++kase) { int N,M,Q; scanf("%d%d%d",&N,&M,&Q); for(int i=0;i<N;i++) for(int j=0;j<N;j++) dist[i][j] = i==j?0:INF; while(M--) { int u,v; long long d; scanf("%d%d%I64d",&u,&v,&d); dist[u][v]=dist[v][u]=d; } floyd(N); MM.init(Q); for(int i=1;i<=Q;i++) scanf("%d%d",&nodes[i].p,&nodes[i].t); for(int i=1;i<=Q;i++) for(int j=1;j<=Q;j++)if(i!=j) if(nodes[i].link(nodes[j])) MM.g[i].push_back(j); printf("Case %d: %d\n",kase,Q-MM.solve()-1); } return 0; }