hdu4966
一开始以为是网络流,各种坑队友,后来才发现是相当裸的最小树形图。
添加一个根,连边到各课程的0级,权值为0。
然后每个课程从(i)级连边到(i-1)级,权值为0.
最后根据课程间的关系再连边。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 555, maxm = 500 * 2000, inf = 1e9;
struct Edge{
int u, v, w;
Edge(){}
Edge(int u, int v, int w):
u(u), v(v), w(w){}
}e[maxm];
int ec;
int lev[55], begid[55], endid[55];
int N;
int mincost[maxn], pre[maxn];
bool makeMin(int root){
for(int i = 1; i <= N; i++) mincost[i] = inf;
for(int i = 0; i < ec; i++){
if(e[i].u == e[i].v) continue;
int v = e[i].v;
if(mincost[v] > e[i].w){
mincost[v] = e[i].w;
pre[v] = e[i].u;
}
}
for(int i = 1; i <= N; i++){
if(i == root) continue;
if(mincost[i] == inf) return false;
}
return true;
}
int vis[maxn];
int id[maxn];
bool existCircle(int root, int &res){
memset(vis, -1, sizeof(vis));
memset(id, -1, sizeof(id));
int ind = 1;
mincost[root] = 0;
for(int i = 1; i <= N; i++){
int v = i;
res += mincost[i];
while(vis[v] != i && v != root && id[v] == -1) {
vis[v] = i, v = pre[v];
}
if(v != root && id[v] == -1){
for(int u = pre[v]; u != v; u = pre[u]) id[u] = ind;
id[v] = ind++;
}
}
if(ind == 1) return false;
for(int i = 1; i <= N; i++)
if(id[i] == -1) id[i] = ind++;
N = ind - 1;
return true;
}
void update(){
for(int i = 0; i < ec; i++){
int v = e[i].v;
e[i].u = id[e[i].u];
e[i].v = id[e[i].v];
if(e[i].u == e[i].v) continue;
e[i].w -= mincost[v];
}
}
int DMST(int root){
int res = 0;
while(1){
if(!makeMin(root)) return -1;
if(!existCircle(root, res)) return res;
update();
root = id[root];
}
return -1;
}
int main(){
// freopen("in", "r", stdin);
// freopen("out", "w", stdout);
int n, m;
while(scanf("%d%d", &n, &m), n&&m){
for(int i = 1; i <= n; i++) scanf("%d", lev+i);
lev[0] = 1, begid[0] = 0;
for(int i = 1; i <= n; i++) begid[i] = begid[i-1] + lev[i-1] + 1;
N = begid[n] + lev[n];
int c, l, d, r, w;
int root = 1;
ec = 0;
for(int i = 1; i <= n; i++)
e[ec++] = Edge(root, begid[i], 0);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= lev[i]; j++){
int u = begid[i] + j, v = u - 1;
e[ec++] = Edge(u, v, 0);
}
}
for(int i = 0; i < m; i++){
scanf("%d%d%d%d%d", &c, &l, &d, &r, &w);
int v = begid[d] + r;
for(int j = l, u = begid[c] + l; j <= lev[c]; u++, j++){
e[ec++] = Edge(u, v, w);
}
}
int ans = DMST(root);
if(~ans) printf("%d\n", ans);
else puts("-1");
}
return 0;
}
hdu4009
一个村子有n个房子,每间房子的坐标为(x,y,z)
如果自己打井,则代价为 z * A
如果从别的房子那里连水管过来,则代价为 两点的曼哈顿距离*B; 如果源点的z比此地的z小,则代价要加上C
求让所有房子都有水的最小代价。(怎么样都能保证每个房子都有水,所以根本不会输出“poor XiaoA”...)
加入根,然后根到每个点的权值为该点自己打井的代价,
然后其他的根据输入建边。
一个优化是,如果某个点从其他点连的边代价比直接自己打井还大,那么就可以不连。
然后就是IO输入优化了。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 1002, maxm = 1002 * 1004, inf = 0x3f3f3f3f;
#define ABS(x) ( (x)>0? (x) : (-(x)) )
struct Edge{
int u, v, w;
Edge(){}
Edge(int u, int v, int w):
u(u), v(v), w(w){}
}e[maxm];
int ec;
int N;
int mincost[maxn], pre[maxn];
bool makeMin(int root){
memset(mincost, 0x3f, sizeof(mincost));
for(int i = 0; i < ec; i++){
if(e[i].u == e[i].v) continue;
int v = e[i].v;
if(mincost[v] > e[i].w){
mincost[v] = e[i].w;
pre[v] = e[i].u;
}
}
for(int i = 1; i <= N; i++){
if(i == root) continue;
if(mincost[i] == inf) return false;
}
return true;
}
int vis[maxn];
int id[maxn];
bool existCircle(int root, int &res){
memset(vis, -1, sizeof(vis));
memset(id, -1, sizeof(id));
int ind = 1;
mincost[root] = 0;
for(int i = 1; i <= N; i++){
int v = i;
res += mincost[i];
while(vis[v] != i && v != root && id[v] == -1) {
vis[v] = i, v = pre[v];
}
if(v != root && id[v] == -1){
for(int u = pre[v]; u != v; u = pre[u]) id[u] = ind;
id[v] = ind++;
}
}
if(ind == 1) return false;
for(int i = 1; i <= N; i++)
if(id[i] == -1) id[i] = ind++;
N = ind - 1;
return true;
}
void update(){
for(int i = 0; i < ec; i++){
int v = e[i].v;
e[i].u = id[e[i].u];
e[i].v = id[e[i].v];
if(e[i].u == e[i].v) continue;
e[i].w -= mincost[v];
}
}
int DMST(int root){
int res = 0;
while(1){
if(!makeMin(root)) return -1;
if(!existCircle(root, res)) return res;
update();
root = id[root];
}
return -1;
}
struct Pos{
int x, y, z;
}p[maxn];
inline int dis(const Pos& a, const Pos& b){
return ABS(a.x-b.x) + ABS(a.y-b.y) + ABS(a.z-b.z);
}
inline int nextInt(){
char ch = ' ';
int res = 0;
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)){
res *= 10;
res += ch - '0';
ch = getchar();
}
return res;
}
int self[maxn];
int main(){
// freopen("in.txt", "r", stdin);
// freopen("out", "w", stdout);
int n, x, y, z;
while(n = nextInt(), x = nextInt(), y = nextInt(), z = nextInt(), n && x && y && z){
ec = 0;
N = n + 1;
for(int i = 1; i <= n; i++) {
p[i].x = nextInt();
p[i].y = nextInt();
p[i].z = nextInt();
}
for(int i = 1; i <= n; i++){
self[i] = p[i].z * x;
e[ec++] = Edge(N, i, self[i]);
}
for(int i = 1; i <= n; i++){
int k;
k = nextInt();
for(int j = 0, v, w; j < k; j++){
v = nextInt();
if(v == i) continue;
w = dis(p[i], p[v]);
w *= y;
if(p[i].z < p[v].z)
w += z;
if(w >= self[v]) continue;
e[ec++] = Edge(i, v, w);
}
}
printf("%d\n", DMST(N));
}
return 0;
}