2020/10/11
kuangbin网络流4题
///链接:https://vjudge.net/problem/UVA-10480
/*题意: n个结点,m路径,现在让s和t号结点不要连接,破坏一条点的花费为k。
题解:最小割。但是注意此题有个区别,他是破坏点,所以我们应该拆点,然后在跑。
*/
#include"stdio.h"
#include"string.h"
#include"stack"
#include"map"
#include"math.h"
#include"iostream"
#include"string"
#include"vector"
#include"queue"
#include"algorithm"
using namespace std;
#define OK printf("\n");
#define Debug printf("this_ok\n");
#define INF 1e18
typedef long long ll;
#define scanll(a,b) scanf("%lld%lld",&a,&b);
#define scanl(a) scanf("%lld",&a);
#define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a);
#define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a);
typedef pair<int,int> PII;
inline int read(){
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
return s * w;
}
const ll mod = 998244353;
const int N = 200000,M = 800000;
const double pi = acos(-1);
const int inf = 1 << 29;
const int dirx[4] = {-1,0,1,0};
const int diry[4] = {0,1,0,-1};
int n,m,t,s,tot;
ll maxflow,sum;
int head[N],ver[M],Next[M],edge[M],d[N];
int w[N];
queue<int> q;
map<string,int> Q;
void add(int x,int y,int z){
ver[++ tot] = y; Next[tot] = head[x]; edge[tot] = z; head[x] = tot;
ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
}
void add1(int x,int y,int z){
ver[++ tot] = y; Next[tot] = head[x]; edge[tot] = z; head[x] = tot;
ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
}
bool bfs(){
memset(d,0,sizeof(d));
while(q.size())q.pop();
q.push(s); d[s] = 1;
while(q.size()){
int x = q.front(); q.pop();
for(int i = head[x]; i; i = Next[i])
if(edge[i] && !d[ver[i]]){
q.push(ver[i]); d[ver[i]] = d[x] + 1;
if(ver[i] == t) return 1;
}
}
return 0;
}
int dinic(int x,ll flow){
if(x == t) return flow;
ll rest = flow,k;
for(int i = head[x]; i && rest; i = Next[i]){
if(edge[i] && d[ver[i]] == d[x] + 1){
k = dinic(ver[i],min(rest,(ll)edge[i]));
if(!k) d[ver[i]] = 0;
edge[i] -= k;
edge[i ^ 1] += k;
rest -= k;
}
}
return flow - rest;
}
int main(){
while(~scanf("%d",&n)){
m = read();
for(int i = 0; i <= n + n + 2; i ++) head[i] = 0;
tot = 1;s = read(); t = read();t += n;
for(int i = 1; i <= n; i ++){
int x = read();
add1(i,i + n,x);
}
for(int i = 1; i <= m; i ++){
int x = read(),y = read();
add(x + n,y,inf);
add(y + n,x,inf);
}
ll flow = 0; maxflow = 0;
while(bfs())
while(flow = dinic(s,inf)) maxflow += flow;
printf("%lld\n",maxflow);
}
}
/*
3
1 2 3
2
2 6
*/
///链接:https://vjudge.net/problem/UVA-10480
/*题意: n个结点,m路径,现在让1和2号结点不要连接,破坏一条路径的花费为k。
题解:最小割,输出路径的话,x和y一开始有路径,x只和1号点连接,y只和2号点连接,那么就是割边。
鉴于此,本题我们用邻接矩阵存储更为方便;
*/
#include"stdio.h"
#include"string.h"
#include"stack"
#include"map"
#include"math.h"
#include"iostream"
#include"vector"
#include"queue"
#include"algorithm"
using namespace std;
#define OK printf("\n");
#define Debug printf("this_ok\n");
#define INF 0x3f3f3f3f
typedef long long ll;
#define scanll(a,b) scanf("%lld%lld",&a,&b);
#define scanl(a) scanf("%lld",&a);
#define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a);
#define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a);
typedef pair<int,int> PII;
inline int read(){
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
return s * w;
}
const ll mod = 998244353;
const int N = 500010,M = 500010;
const int inf = 1 << 29;
const int maxn=1e3+10;
int n,m;
int mp[maxn][maxn];//初始流量
int flow[maxn][maxn];//最大流
int path[maxn];//记录路径
int a[maxn];//i点在最大流中的流量
int start,End;
int x[maxn],y[maxn];
int maxflow()
{
queue<int> q;
memset(flow,0,sizeof flow);
int max_flow=0;
while(true){
memset(a,0,sizeof a);//清空标记
a[start]=INF;//源点权值无限大
while(!q.empty()) q.pop();
q.push(start);
while(!q.empty()){
int temp=q.front();
q.pop();
for(int i=1;i<=n;i++){
//未走过且流量小于他的权值
if(!a[i]&&flow[temp][i]<mp[temp][i])
{
path[i]=temp;//记录前一个点
a[i]=min(a[temp],mp[temp][i]-flow[temp][i]);
q.push(i);
}
}
}
if(a[End]==0) break;
//更新剩余网络
for(int i=End;i!=start;i=path[i]){
flow[path[i]][i]+=a[End];//反向边加
flow[i][path[i]]-=a[End];//正向边减
}
max_flow+=a[End];
}
return max_flow;
}
int main()
{
while(~scanf("%d%d",&n,&m)){
if(n == 0) break;
memset(mp,0,sizeof mp);
for(int i=1;i<=m;i++)
{
int u = read(),v = read(),w = read();
mp[u][v]=mp[v][u]=w;///无向路径
x[i]=u; y[i]=v;
}
start=1;End=2;
int flow=maxflow();
for(int i=1;i<=m;i++){//枚举每一条边的两个点
//有一点的权值为0,说明当前点被删除
if((!a[x[i]]&&a[y[i]])||(a[x[i]]&&!a[y[i]]))
printf("%d %d\n",x[i],y[i]);
}
printf("\n");
}
return 0;
}
///链接:http://acm.hdu.edu.cn/showproblem.php?pid=4280
/*题意: 在最西边的点走到最东边的点最大容量。
题解:ISAP模板题,Dinic过不了。
*/
#include"stdio.h"
#include"string.h"
#include"stack"
#include"map"
#include"math.h"
#include"iostream"
#include"string"
#include"vector"
#include"queue"
#include"algorithm"
using namespace std;
#define OK printf("\n");
#define Debug printf("this_ok\n");
#define INF 1e18
typedef long long ll;
#define scanll(a,b) scanf("%lld%lld",&a,&b);
#define scanl(a) scanf("%lld",&a);
#define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a);
#define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a);
typedef pair<int,int> PII;
inline int read(){
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
return s * w;
}
const ll mod = 998244353;
const int N = 200000,M = 800000;
const double pi = acos(-1);
const int inf = 1 << 29;
const int dirx[4] = {-1,0,1,0};
const int diry[4] = {0,1,0,-1};
int n,m,t,s,tot;
ll maxflow,sum;
int head[N],ver[M],Next[M],edge[M],d[N];
int w[N];
queue<int> q;
map<string,int> Q;
void add(int x,int y,int z){
ver[++ tot] = y; Next[tot] = head[x]; edge[tot] = z; head[x] = tot;
ver[++ tot] = x; edge[tot] = z; Next[tot] = head[y]; head[y] = tot;
}
bool bfs(){
memset(d,0,sizeof(d));
while(q.size())q.pop();
q.push(s); d[s] = 1;
while(q.size()){
int x = q.front(); q.pop();
for(int i = head[x]; i; i = Next[i])
if(edge[i] && !d[ver[i]]){
q.push(ver[i]); d[ver[i]] = d[x] + 1;
if(ver[i] == t) return 1;
}
}
return 0;
}
int dinic(int x,ll flow){
if(x == t) return flow;
ll rest = flow,k;
for(int i = head[x]; i && rest; i = Next[i]){
if(edge[i] && d[ver[i]] == d[x] + 1){
k = dinic(ver[i],min(rest,(ll)edge[i]));
if(!k) d[ver[i]] = 0;
edge[i] -= k;
edge[i ^ 1] += k;
rest -= k;
}
}
return flow - rest;
}
int main(){
int T = read();
while(T --){
n = read(); m = read();
tot = 1;s = 1; t = 1;
int tmax = -inf, tmin = inf;
s = t= 1;
for(int i = 1; i <= n; i ++) {
int x = read(),y = read();
if(x >= tmax) tmax = x, t = i;
if(x <= tmin) tmin = x, s = i;
head[i] = 0;
}
for(int i = 1; i <= m; i ++){
int x = read(),y = read(),w = read();
add(x,y,w);
}
ll flow = 0; maxflow = 0;
while(bfs())
while(flow = dinic(s,inf)) maxflow += flow;
printf("%lld\n",maxflow);
}
}
/*
3
1 2 3
2
2 6
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
typedef long long LL;
struct Edge {
int u, v;
LL cap;
Edge () {}
Edge (int u, int v, LL cap) : u(u), v(v), cap(cap) {}
}edge[N*4];
vector<int> G[N];
int dis[N], cur[N], num[N], pre[N], tot, S, T;
void Add(int u, int v, int cap) {
edge[tot] = Edge(u, v, cap);
G[u].push_back(tot++);
edge[tot] = Edge(v, u, cap);
G[v].push_back(tot++);
}
int BFS() { // 逆向BFS
memset(dis, -1, sizeof(dis));
queue<int> que; que.push(T);
dis[T] = 0;
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = 0; i < G[u].size(); i++) {
Edge &e = edge[G[u][i]];
if(dis[e.v] == -1) {
dis[e.v] = dis[u] + 1;
que.push(e.v);
}
}
}
return ~dis[S];
}
int DFS() { // 通过pre数组回溯更新流量
int u = T; int flow = INF;
while(u != S) {
Edge &e = edge[pre[u]];
if(e.cap < flow) flow = e.cap;
u = e.u;
} u = T;
while(u != S) {
Edge& e1 = edge[pre[u]];
Edge& e2 = edge[pre[u]^1];
e1.cap -= flow; e2.cap += flow;
u = e1.u;
}
return flow;
}
int ISAP(int n) {
if(!BFS()) return 0; // 从汇点到源点逆向BFS初始化dis数组
memset(num, 0, sizeof(num));
memset(cur, 0, sizeof(cur)); // 当前弧优化
for(int i = 1; i <= n; i++)
if(~dis[i]) num[dis[i]]++; // 当前距离为dis[i]的结点数
int ans = 0, u = S;
while(dis[S] < n) {
if(u == T) ans += DFS(), u = S; // 回溯之前的结点并把更新流量
int flag = 0;
for(int i = 0; i < G[u].size(); i++) {
Edge &e = edge[G[u][i]];
if(dis[e.v] + 1 == dis[u] && e.cap > 0) { // 可以增广
pre[e.v] = G[u][i]; cur[u] = i;
flag = 1; u = e.v;
break;
}
}
if(!flag) { // 不能增广,retreat
if(--num[dis[u]] == 0) break; // gap优化
int md = n;
for(int i = 0; i < G[u].size(); i++) {
Edge &e = edge[G[u][i]];
if(e.cap > 0 && dis[e.v] < md) {
md = dis[e.v]; cur[u] = i;
}
}
num[dis[u] = md + 1]++;
if(u != S) u = edge[pre[u]].u;
}
}
return ans;
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
int n, m;
scanf("%d%d", &n, &m);
tot = 0; for(int i = 0; i <= n; i++) G[i].clear();
int u, v, c, west = 100000000, east = -10000000;
for(int i = 1; i <= n; i++) {
scanf("%d%d", &u, &v);
if(west > u) west = u, S = i;
if(east < u) east = u, T = i;
}
for(int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &c);
Add(u, v, c); // 无向图的话反向边的cap也是c
}
printf("%d\n", ISAP(n));
}
return 0;
}
*/
///链接:https://vjudge.net/problem/POJ-1087
/*题意: 有m个设备需要插座(给出了每个设备需要的插座型号),但是现在只有n个插座(任意两个插座类型不相同,因为题目说每种类型插座就一个),且给你k个转换器(转换器(u,v)可以使得插座v转接到u上),问你最多有几个设备没有插座可用?
题解:建图:
源点s(编号0)到每个设备i有边 (s,i,1).
每个插座到j到汇点t(编号n+m+1)有边 (j,t,1)
如果设备i对应的插座是j,那么有边(i,j,1)
如果转换器对应(u,v)(说明可以把插座v转接到u上),那么有边(u,v,INF) (因为转换器无限个,且它可以把原本需要u插座的电器连到v插座上)
*/
#include"stdio.h"
#include"string.h"
#include"stack"
#include"map"
#include"math.h"
#include"iostream"
#include"string"
#include"vector"
#include"queue"
#include"algorithm"
using namespace std;
#define OK printf("\n");
#define Debug printf("this_ok\n");
#define INF 1e18
typedef long long ll;
#define scanll(a,b) scanf("%lld%lld",&a,&b);
#define scanl(a) scanf("%lld",&a);
#define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a);
#define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a);
typedef pair<int,int> PII;
inline int read(){
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
return s * w;
}
const ll mod = 998244353;
const int N = 50010,M = 300010;
const double pi = acos(-1);
const int inf = 1 << 29;
const int dirx[4] = {-1,0,1,0};
const int diry[4] = {0,1,0,-1};
int n,m,t,s,tot;
ll maxflow,sum;
int head[N],ver[M],Next[M],edge[M],d[N];
int w[N];
queue<int> q;
map<string,int> Q;
void add(int x,int y,int z){
ver[++ tot] = y; Next[tot] = head[x]; edge[tot] = z; head[x] = tot;
ver[++ tot] = x; edge[tot] = 0; Next[tot] = head[y]; head[y] = tot;
}
bool bfs(){
memset(d,0,sizeof(d));
while(q.size())q.pop();
q.push(s); d[s] = 1;
while(q.size()){
int x = q.front(); q.pop();
for(int i = head[x]; i; i = Next[i])
if(edge[i] && !d[ver[i]]){
q.push(ver[i]); d[ver[i]] = d[x] + 1;
if(ver[i] == t) return 1;
}
}
return 0;
}
int dinic(int x,ll flow){
if(x == t) return flow;
ll rest = flow,k;
for(int i = head[x]; i && rest; i = Next[i]){
if(edge[i] && d[ver[i]] == d[x] + 1){
k = dinic(ver[i],min(rest,(ll)edge[i]));
if(!k) d[ver[i]] = 0;
edge[i] -= k;
edge[i ^ 1] += k;
rest -= k;
}
}
return flow - rest;
}
int main(){
n = read();
tot = 1;int top = 0; s = 0; t = 510;
int p1[120] = {0},p2[120] = {0};
for(int i = 1; i <= n; i ++){
char str; cin >> str;
p1[str - 'A' + 1] ++;
}
for(int i = 1; i < 120; i ++){
if(!p1[i]) continue;
add(i,t,p1[i]);
}
m = read();
for(int i = 1; i <= m; i ++){
string name; char str;
cin >> name >> str;
p2[str - 'A' + 1] ++;
}
for(int i = 1; i < 120; i ++){
if(!p2[i]) continue;
add(s,i + 120,p2[i]);
// add(i + 120,i,inf);
}
int q = read();
for(int i = 1; i <= q; i ++){
char s1,s2; cin >> s1 >> s2;
add(s1 - 'A' + 1 + 120,s2 - 'A' + 1 + 120,inf);
}
for(int i = 1; i < 120; i ++) add(i + 120,i,inf);
ll flow = 0;
while(bfs())
while(flow = dinic(s,inf)) maxflow += flow;
printf("%lld\n",m - maxflow);
}
/*
3
1 2 3
2
2 6
*/
浙公网安备 33010602011771号