贴这题的题解有两个目的:
1.匈牙利算法O(nm)是一个很松的上届
2.匈牙利算法的建边和建点可以缩小为一半。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
const lint inf= 0x3f3f3f3f;
const lint maxn = 2001;
const lint maxm = 1000005;
lint dist[maxn][maxn];
lint tot,he[maxn],ne[maxm],ver[maxm];
void add( lint x,lint y ){
ver[++tot] = y;
ne[tot] = he[x];
he[x] = tot;
}
lint xs[maxn],xb[maxn],f[maxn];
LL a[maxn],d[maxn];
void floyd( lint n){
for( lint k = 1;k <= n;k++ ){
for( lint i = 1;i <= n;i++ ){
for( lint j = 1;j <= n;j++ ){
dist[i][j] = min( dist[i][j],dist[i][k]+dist[k][j] );
}
}
}
}
void init(lint n){
memset( dist,0x3f,sizeof(dist) );
for( lint i = 1; i<= n;i++ ) dist[i][i] = 0;
tot = 1;
}
lint vis[maxn],match[maxn];
bool dfs( lint x){
for( lint cure = he[x];cure;cure = ne[cure] ){
lint y = ver[cure];
if( !vis[y] ){
vis[y] = 1;
if(!match[y] || dfs( match[y] ) ){
match[y] = x;return true;
}
}
}
return false;
}
int main(){
lint n,m;
scanf("%d%d",&n,&m);
init(n);
for( lint x,y,i = 1;i <= m;i++ ){
scanf("%d%d",&x,&y);
dist[x][y] = dist[y][x] = 1;
}
lint s,b,k,h;
scanf("%d%d%d%d",&s,&b,&k,&h);
for( lint i = 1;i <= s;i++ ){
scanf("%d%d%d",&xs[i],&a[i],&f[i]);
}
for( lint i = 1;i <= b;i++ ){
scanf("%d%d",&xb[i],&d[i]);
}
floyd(n);
for( lint i = 1;i <= s;i++ ){
for( lint j = 1;j <= b;j++ ){
if( dist[ xs[i] ][ xb[j] ] <= f[i] && a[i] >= d[j] ){
add( i,j );
}
};
}
lint ans = 0;
for( lint i = 1;i <= s;i++ ){
memset( vis,0,sizeof(vis) );
if( dfs(i) ) ans++;
}
LL res1 = (LL)s*h;
LL res2 = (LL)ans*k;
printf("%I64d\n",min(res1,res2));
return 0;
}