题意:
1499 图
2.0 秒 262,144.0 KB 80 分 5级题
给一个无向图,你要将这些点分成A、B两个集合,使得满足A的导出子图是一个完全图,而B的导出子图是一个没有边的图。
但是事实上你不一定能够做到,所以你允许有错误。我们定义一个完美值为:
1.如果A中两点有边相连,则增加|i-j|的完美值。
2.如果B中两点无边相连,则增加|i-j|的完美值。
(i,j是这两个点的编号)
那么,我们让完美值最大就可以了。
N <= 1000, M <= 200000
输入
N, M 表示点数和边数
M行,
u,v表示一条无向边。
(不会有重边和自环)
输出
一个数,表示最大的完美值。
输入样例
5 5
1 2
1 3
1 4
1 5
2 3
输出样例
11
思路:
5555,本菜鸡的最大流和最小割确实是不熟练。。。。5555,所以我根本不知道这是最小割,完败!!!
(1)虽然已经看过了,那么我们再来熟悉一下什么是最小割
(2)那么我们再康康这道题的题意:把n个顶点划分为两个集合A和B,一个集合的导出子图是完全图,另一个的导出子图是没有边的图。定义一个完美值为:1.如果A中两点有边相连,则增加|i-j|的完美值。2.如果B中两点无边相连,则增加|i-j|的完美值。(i,j是这两个点的编号),求最大的完美值。
(3)正确解法就是将顶点划分为S和T两个集合,S是两两之间没有边的集合,T是两两之间都有边的集合,那么我们可以这样求
明显的最小割!!!但是我却不会!!!现在还行吧
代码实现:
//正规解法
#include <cstdio>
#include<iostream>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const ll inf = 1e18;
int n,m;
struct node{
int to;
int w;
int rev;//反向边的位置
};
vector<node>G[maxn];
int dep[maxn];
int cr[maxn];
queue<int> q;
int vis[1005][1005];
void add(int u,int v,int w){
G[u].push_back((node){v,w,G[v].size()});
G[v].push_back((node){u,w,G[u].size() - 1});
}
bool bfs(int s,int t){
memset(dep,0,sizeof(dep));
memset(cr,0,sizeof(cr));
while(!q.empty()) q.pop();
dep[s] = 1; q.push(s);
while(!q.empty()){
int now = q.front(); q.pop();
int len = G[now].size();
for(int i = 0;i < len;i++){
node cur = G[now][i];
if(cur.w > 0&&!dep[cur.to]){//寻找可行的路径
q.push(cur.to); dep[cur.to] = dep[now] + 1;
}
}
}
return dep[t] != 0;
}
ll dfs(int s,int t,ll mx){
if(s == t) return mx;
ll flow = 0; int len = G[s].size(); int tmp;
for(int &i = cr[s];i < len;i++){//接着上一次查找的位置继续往下找
node &e = G[s][i];
if(dep[s] + 1 == dep[e.to]&&e.w > 0){//可能可行的路径
tmp = dfs(e.to,t,min(mx,(ll)e.w));
if(tmp != 0){
mx -= tmp; e.w -= tmp; flow += tmp;
G[e.to][e.rev].w += tmp;
}
if(mx == 0) break;
}
}
if(flow == 0) dep[s] = 0;
return flow;
}
ll dinic(int s,int t){
ll flow = 0;
while(bfs(s,t)) flow += dfs(s,t,inf);//最大流累加
return flow;
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i = 1;i <= n;i++) G[i].clear();
int u,v;
for(int i = 1;i <= m;i++){
scanf("%d%d",&u,&v);
vis[u][v] = 1;
vis[v][u] = 1;
}
int sum = 0;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
sum = sum + abs(i - j);
}
}
int s = 0; int t = n + 1;
for(int i = 1;i <= n;i++){
for(int j = i + 1;j <= n;j++){
add(i,j,j - i);
if(vis[i][j]){
add(i,t,j - i);
add(j,t,j - i);
}
else{
add(s,i,j - i);
add(s,j,j - i);
}
}
}
printf("%lld\n",(sum - dinic(s,t)) / 2);
}
return 0;
}