poj3216 Repairing Company 二分匹配之最小路径覆盖+最短路
http://poj.org/problem?id=3216
题目说的是一个城市里面有Q个点,有M项工作,每个工作有个工作地点pi,最晚开始时间ti,和工作需要的时间di.
从城市中的任意一个点到另一个点的直接时间又一个矩阵给出。不连通为-1.注意间接联通是被允许的。
我再这个题上哉了2次,汗啊。我总是以为二分图的顶点时基于城市中的点的,但实际上时基于工作。
这一题首先对给定的图做一次floyd,这样就能求出两个点之间最少需要走的时间。
然后判断两个工作之间是否存在先后关系
最后做最小路径覆盖即可。注意这里的顶点数应该是工作数!这一题值得重点注意!!!
Source Code
Problem: 3216 | User: 541780774 | |
Memory: 440K | Time: 79MS | |
Language: G++ | Result: Accepted |
Source Code
#include<stdio.h> #include<stdlib.h> #include<string.h> int nx, ny,p[21][21]; // X的點數目、Y的點數目 int mx[201], my[201]; // X各點的配對對象、Y各點的配對對象 bool vy[201]; // 紀錄Graph Traversal拜訪過的點 bool adj[201][201]; // 精簡過的adjacency matrix // 以DFS建立一棵交錯樹 bool DFS(int x) { for (int y=0; y<ny; ++y) if (adj[x][y] && !vy[y]) { vy[y] = true; // 找到擴充路徑 if (my[y] == -1 || DFS(my[y])) { mx[x] = y; my[y] = x; return true; } } return false; } int bipartite_matching() { // 全部的點初始化為未匹配點。 memset(mx, -1, sizeof(mx)); memset(my, -1, sizeof(my)); // 依序把X中的每一個點作為擴充路徑的端點, // 並嘗試尋找擴充路徑。 int c = 0; for (int x=0; x<nx; ++x) // if (mx[x] == -1) // x為未匹配點,這行可精簡。 { // 開始Graph Traversal memset(vy, false, sizeof(vy)); if (DFS(x)) c++; } return c; } void Floyd(int n) { int i,j,k; for(k=0;k<n;k++) for(i=0;i<n;i++) for(j=0;j<n;j++) { if((p[i][j]>p[i][k]+p[k][j]||p[i][j]==-1)&&i!=j&&p[i][k]!=-1&&p[k][j]!=-1) p[i][j]=p[i][k]+p[k][j]; } } main() { int i,j,Q,M; struct{ int a; int b; int c; }h[201]; while(scanf("%d%d",&Q,&M),Q!=0&&M!=0) { memset(adj,0,sizeof(adj)); for(i=0;i<Q;i++) for(j=0;j<Q;j++) scanf("%d",&p[i][j]); Floyd(Q); for(i=0;i<M;i++) { scanf("%d%d%d",&h[i].a,&h[i].b,&h[i].c); h[i].c=h[i].b+h[i].c; } for(i=0;i<M;i++) for(j=0;j<M;j++) { if(h[i].c>h[j].b||p[h[i].a-1][h[j].a-1]==-1||i==j) continue; else if(h[i].a==h[j].a) adj[i][j]=1; else if(h[i].c+p[h[i].a-1][h[j].a-1]<=h[j].b) adj[i][j]=1; } nx=ny=M; printf("%d\n",M-bipartite_matching()); } system("pause"); }