争夺 & KM思想
题意:
给一张二分图,每个点与两个特定点又一条边相连,边权非负,让你给这个二分图每个点一个顶标,让每一条边两端顶标和大于等于这条边。求出最小顶标和。
这当然是翻译过的题目。。。
原题:
小Y和小P无聊的时候就喜欢玩游戏,但是每次小P都输给了小Y。终于有一天,你看不过去了,决定帮小P一把。
游戏是这样的,一个N*M的棋盘(保证n或m中,至少有一个为偶数)。相邻格子之间有一个给定的正整数权值。要你给这些格子填上一些值,使得相邻两个格子本身的权值之和,要大于等于他们之间给定的权值。并且要使得所有格子权值之和最小。
不过也挺显然的。。。当然在你学完KM后对这种思想还是非常敏感。。如果没学过会怎么乱搞呢?。。。因确斯汀。
SOL:
还有题解?。。。这不就跑个KM顶标什么的都出来了。。。数据较大用个领接表。。也就复习一下KM
CODE:
/*==========================================================================
# Last modified: 2016-03-04 09:11
# Filename: t2.cpp
# Description:
==========================================================================*/
#define me AcrossTheSky
#include <cstdio>
#include <cmath>
#include <ctime>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm> #include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector> #define lowbit(x) (x)&(-x)
#define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++)
#define FORP(i,a,b) for(int i=(a);i<=(b);i++)
#define FORM(i,a,b) for(int i=(a);i>=(b);i--)
#define ls(a,b) (((a)+(b)) << 1)
#define rs(a,b) (((a)+(b)) >> 1)
#define getlc(a) ch[(a)][0]
#define getrc(a) ch[(a)][1] #define maxn 11050
#define maxm 50000
#define pi 3.1415926535898
#define _e 2.718281828459
#define INF 1070000000
using namespace std;
typedef long long ll;
typedef unsigned long long ull; template<class T> inline
void read(T& num) {
bool start=false,neg=false;
char c;
num=0;
while((c=getchar())!=EOF) {
if(c=='-') start=neg=true;
else if(c>='0' && c<='9') {
start=true;
num=num*10+c-'0';
} else if(start) break;
}
if(neg) num=-num;
}
/*==================split line==================*/
struct Edge{
int to,len;
}e[maxm];
int s[maxn],t[maxn],slack[maxn],lx[maxn],ly[maxn];
bool color[maxn],S[maxn],T[maxn],vis[maxn];
int out[5050][5050],link[maxn],ord[maxn],first[maxn],next[maxm];
int sumt=0,sums=0,sume=0;
int n,m;
void addedge(int x,int y,int l){
sume++; e[sume].to=y; e[sume].len=l;
next[sume]=first[x]; first[x]=sume;
}
void updata(){
int a=INF;
FORP(j,1,sumt) if (!T[j]) a=min(a,slack[j]);
FORP(i,1,sums) if (S[i]) lx[i]-=a;
FORP(i,1,sumt) if (T[i]) ly[i]+=a;
else slack[i]-=a;
return;
}
bool match(int x){
S[x]=true;
//FORP(i,1,sumt){
for (int p=first[s[x]]; p!=-1; p=next[p]){
int i=ord[e[p].to];
if (T[i]) continue;
if (lx[x]+ly[i]==e[p].len){//way[s[x]][t[i]]){
T[i]=true;
if (!link[i] || match(link[i])){
link[i]=x;
return true;
}
}
else slack[i]=min(slack[i],lx[x]+ly[i]-e[p].len);//way[s[x]][t[i]]);
}
return false;
}
void KM(){
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
memset(link,0,sizeof(link));
FORP(i,1,sums)
for (int j=first[s[i]];j!=-1;j=next[j])
lx[i]=max(lx[i],e[j].len);
//FORP(j,1,sumt) lx[i]=max(lx[i],way[s[i]][t[j]]); FORP(i,1,sums){
FORP(j,1,sumt) slack[j]=INF;
while (1){
memset(S,false,sizeof(S));
memset(T,false,sizeof(T));
if (match(i)) break;
else updata();
}
}
}
void get(int node,int v){
int x=node/m+1,y=node%m;
if (y==0) y=m,x--;
out[x][y]=v;
}
void paint(int x,int y,bool fa){
int node=(x-1)*m+y;
if (vis[node]) return;
vis[node]=true;
color[node]=!fa;
if (color[node]) s[++sums]=node,ord[node]=sums;
else t[++sumt]=node,ord[node]=sumt;
if (y==0) y=m,x--;
if (x<n) paint(x+1,y,color[node]);
if (y<m) paint(x,y+1,color[node]);
}
int main(){
read(n); read(m);
memset(first,-1,sizeof(first));
FORP(i,1,n){
FORP(j,1,2*m) {
int x; read(x);
if (j>2*(m-1)+1 || (i==n && j%2==1)) continue;
if (j%2==1) {
int node1=(i-1)*m+j/2+1;
int node2=node1+m;
addedge(node1,node2,x);
addedge(node2,node1,x);
}
else {
int node1=(i-1)*m+j/2;
int node2=node1+1;
addedge(node2,node1,x);
addedge(node1,node2,x);
}
}
}
memset(vis,false,sizeof(vis));
paint(1,1,false); KM();
int ans=0;
FORP(i,1,sums) {ans+=lx[i]; get(s[i],lx[i]);}
FORP(i,1,sumt) {ans+=ly[i]; get(t[i],ly[i]);}
printf("%d\n",ans);
FORP(i,1,n){
FORP(j,1,m) printf("%d ",out[i][j]);
cout << endl;
}
}
争夺 & KM思想的更多相关文章
- POJ 3686 & 拆点&KM
题意: 有n个订单,m个工厂,第i个订单在第j个工厂生产的时间为t[i][j],一个工厂可以生产多个订单,但一次只能生产一个订单,也就是说如果先生产a订单,那么b订单要等到a生产完以后再生产,问n个订 ...
- 二分图 最大权匹配 km算法
这个算法的本质还是不断的找增广路: KM算法的正确性基于以下定理:若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最 ...
- 【HDU 2255】奔小康赚大钱 (最佳二分匹配KM算法)
奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- KM算法专题
原文:http://972169909-qq-com.iteye.com/blog/1184514 题目地址:这里. 1)求图中所有环的总长度(环的长度不唯一)的最小值.当无法得到完备匹配时说明环不存 ...
- HDU 2255 奔小康赚大钱 KM算法的简单解释
KM算法一般用来寻找二分图的最优匹配. 步骤: 1.初始化可行标杆 2.对新加入的点用匈牙利算法进行判断 3.若无法加入新编,修改可行标杆 4.重复2.3操作直到找到相等子图的完全匹配. 各步骤简述: ...
- 二分图匹配之最佳匹配——KM算法
今天也大致学了下KM算法,用于求二分图匹配的最佳匹配. 何为最佳?我们能用匈牙利算法对二分图进行最大匹配,但匹配的方式不唯一,如果我们假设每条边有权值,那么一定会存在一个最大权值的匹配情况,但对于KM ...
- 【原创】我的KM算法详解
0.二分图 二分图的概念 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V, E)是一个无向图.如果顶点集V可分割为两个互不相交的子集X和Y,并且图中每条边连接的两个顶点一个在X中,另一个在Y ...
- KM算法及其应用
在二分图匹配中有最大匹配问题,使用匈牙利算法或者网络流相关算法解决,如果给每条边增加一个权值,求权值和最大的匹配方案就叫做最大权匹配问题.其实之前所说的最大匹配就是权值为1的最大权匹配. 求最大权完备 ...
- (转)二分图匹配匈牙利算法与KM算法
匈牙利算法转自于: https://blog.csdn.net/dark_scope/article/details/8880547 匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名 ...
随机推荐
- Delphi函数的返回值(注意这里与C/C++等语言有差异)
在C/C++等语言中,函数执行到 return 部分之后,将立即停止函数的执行,并返回值 但是在Delphi中不同 函数中,执行到result时,并不同于比如 C/C++ 中的 return,跳出函数 ...
- 【转载】Pyqt QSplitter分割窗口
转载来自: http://blog.sina.com.cn/s/blog_4b5039210100h3ih.html 分割窗口在应用程序中经常用到,它可以灵活分布窗口布局,经常用于类似文件资源管理器的 ...
- saltapi中expr_form参数的使用
以前,一直用compound参数, 现在,想要并行执行salt命令,那list就派上用场了. 同时传多个主机列表,用逗号分隔,然后,用list参数传,就好. [root@c1773 deployop] ...
- android 入门-R文件的死与活
1.图片的名字Btn_Play R文件死了. 1.答:修改图片的名字btn_play R文件活了.
- 安装wine的问题
- poj 3264 【线段树】
此题为入门级线段树 题意:给定Q(1<=Q<=200000)个数A1A2…AQ,多次求任一区间Ai-Aj中最大数和最小数的差 #include<algorithm> #incl ...
- xUtils,butterknife...处理findviewbyid
在写android中,经常要出现大量的findviewbyid et_path = (EditText) findViewById(R.id.et_path); tv_info = (TextVi ...
- Linux学习笔记(3)Linux常用命令之文件处理命令
Linux的命令格式一般为:命令 [-选项] [参数],如ls -la /etc,需要注意几点:1)个别命令使用不遵循此格式:2)当有多个选项时,可以写在一起:3)存在简化选项(-)与完整选项,如-a ...
- codeforces724-B. Batch Sort
想着想着就忘了有什么问题没解决,坑啊 一开始读错题意了,而且一着急写了两大段差不多的代码,冗余度啊,不说了.. 显然的一点,给的数据是绝对离散的,每行都是1~m的排列 难点一.如何移动能使未排序的数组 ...
- ettercap局域网内DNS欺骗(隔壁的哥们轻一点 ...)
转自:http://www.cnblogs.com/hkleak/p/5043063.html 笔记一:ettercap是什么? 我们在对WEB安全检测的时候都会用到Cain和netfuke这两款工具 ...