二分图的一些题目合集

妈蛋状态都被狗吃了,已经开始不自觉对着电脑发呆……被几道二分图的题亮瞎了双眼(这么弱可是gdkoi只剩一个月gdoi只剩100+天……!!)

wikioi1222信与信封问题

二分图,但是判断两个合集中的某两个点是不是只能连在一起。那么我们就在跑一边最大匹配后直接用是否可以增广来判断。如果可以增广那么这两个点是有其他方式连在一起的,否则这两个点就必须连在一起。具体做法是先去掉这两个点的边,不过那么match数组也要跟着改一下。

var
  map:array[0..200,0..200]of boolean;
  matchx,matchy:array[0..200]of longint;
  chose:array[0..200]of boolean;
  n:longint;

function dfs(x:longint):boolean;
var
  i:longint;
begin
  for i:=1 to n do
    if map[x,i] and chose[i] then begin
      chose[i]:=false;
      if (matchx[i]=0) or dfs(matchx[i]) then begin
        matchx[i]:=x;
        matchy[x]:=i;
        exit(true);
      end;
    end;
  exit(false);
end;

procedure into;
var
  j,k:longint;
begin
  readln(n);
  fillchar(map,sizeof(map),true);
  while true do begin
    readln(j,k);
    if j=0 then break;
    map[j,k]:=false;
  end;
end;

function work:boolean;
var
  ans,i,j:longint;
  flag:boolean;
begin
  for i:=1 to n do begin
    fillchar(chose,sizeof(chose),true);
    if not dfs(i) then exit(false);
  end;
  flag:=false;
  for i:=1 to n do begin
    fillchar(chose,sizeof(chose),true);
    j:=matchy[i];
    map[i,j]:=false;
    matchx[j]:=0;
    matchy[i]:=0;
    if not dfs(i) then begin
      writeln(i,‘ ‘,j);
      matchx[j]:=i;
      matchy[i]:=j;
      flag:=true;
    end;
    map[i,j]:=true;
  end;
  exit(flag);
end;

begin
  into;
  if not work then writeln(‘none‘);
  readln;
end.

bzoj2150: 部落战争

最小路径覆盖,等于=点数-最大匹配,把有向图转为二分图的做法就是把每个点分成两个点,一个是入点,如果有边指向这个点则指向入点,一个是出点,如果这个点有指向其他点则出点。这样把原图的边转化一下,然后就直接最大匹配。

type
  arr=record
    toward,next:longint;
  end;

const
  maxm=10000;
  maxn=5000;
var
  edge:array[0..maxm]of arr;
  first,match:array[0..maxn]of longint;
  map:array[0..100,0..100]of boolean;
  chose:array[0..maxn]of boolean;
  n,m,tot,ans:longint;

function check(x,y:longint):boolean;
begin
  exit( (x>=1) and (x<=n) and (y>=1) and (y<=m) and map[x,y] );
end;

function calc(x,y:longint):longint;
begin
  exit((x-1)*m+y);
end;

procedure addedge(j,k:longint);
begin
  inc(tot);
  edge[tot].toward:=k;
  edge[tot].next:=first[j];
  first[j]:=tot;
end;

function dfs(x:longint):boolean;
var
  i,too:longint;
begin
  i:=first[x];
  while i>0 do begin
    too:=edge[i].toward;
    if chose[too] then begin
      chose[too]:=false;
      if (match[too]=0) or dfs(match[too]) then begin
        match[too]:=x;
        exit(true);
      end;
    end;
    i:=edge[i].next;
  end;
  exit(false);
end;

procedure into;
var
  i,j,r,l:longint;
  ch:char;
begin
  readln(n,m,l,r);
  for i:=1 to n do begin
    for j:=1 to m do begin
      read(ch);
      if ch=‘.‘ then map[i,j]:=true
        else inc(ans);
    end;
    readln;
  end;
  for i:=1 to n do
    for j:=1 to m do begin
      if check(i+l,j-r) then addedge(calc(i,j),calc(i+l,j-r));
      if check(i+r,j-l) then addedge(calc(i,j),calc(i+r,j-l));
      if check(i+l,j+r) then addedge(calc(i,j),calc(i+l,j+r));
      if check(i+r,j+l) then addedge(calc(i,j),calc(i+r,j+l));
    end;
end;

procedure work;
var
  i,j:longint;
begin
  for i:=1 to n do
    for j:=1 to m do
      if map[i,j] then begin
        fillchar(chose,sizeof(chose),true);
        if dfs(calc(i,j)) then inc(ans);
      end;
  writeln(n*m-ans);
end;

begin
  into;
  work;
  readln;
  readln;
End.

bzoj1191: [HNOI2006]超级英雄Hero

直接跑匈牙利,不能增广就退出就行了。

const
  maxn=1000;

var
  match:array[0..maxn]of longint;
  chose:array[0..maxn]of boolean;
  too:array[0..maxn,1..2]of longint;
  i,j,n,m:longint;

function dfs(x:longint):boolean;
var
  i,j:longint;
begin
  for i:=1 to 2 do begin
    j:=too[x,i];
    if chose[j] then begin
      chose[j]:=false;
      if (match[j]=0) or dfs(match[j]) then begin
        match[j]:=x;
        exit(true);
      end;
    end;
  end;
  exit(false);
end;

begin
  readln(n,m);
  for i:=1 to m do
    readln(too[i,1],too[i,2]);
  for i:=1 to m do begin
    fillchar(chose,sizeof(chose),true);
    if not dfs(i) then begin
      writeln(i-1);
      break;
    end;
    if i=m then writeln(m);
  end;
end.

bzoj1854: [Scoi2010]游戏

这题有两个做法,一个是二分图,一个是并查集

二分图,类似超级英雄,直接搞。然后就会tle,问题在于那个fillchar(chose),这个太耗时了,然后就把chose改为记录第几次更新,这样每次就不用fillchar(chose)一边。这是一个新姿势。

type
  arr=record
    toward,next:longint;
  end;

const
  maxm=1000000;
  maxn=20000;

var
  first:array[0..maxn]of longint;
  match,chose:array[0..maxm]of longint;
  edge:array[0..maxm*2]of arr;
  n,tot,sum:longint;

procedure addedge(j,k:longint);
begin
  inc(tot);
  edge[tot].toward:=k;
  edge[tot].next:=first[j];
  first[j]:=tot;
end;

function dfs(x:longint):boolean;
var
  i,too:longint;
begin
  i:=first[x];
  while i>0 do begin
    too:=edge[i].toward;
    if chose[too]<>sum then begin
      chose[too]:=sum;
      if (match[too]=0) or dfs(match[too]) then begin
        match[too]:=x;
        exit(true);
      end;
    end;
    i:=edge[i].next;
  end;
  exit(false);
end;

procedure work;
var
  i,j,k:longint;
begin
  readln(n);
  for i:=1 to n do begin
    readln(j,k);
    addedge(j,i);
    addedge(k,i);
  end;
  fillchar(chose,sizeof(chose),0);
  sum:=1;
  for i:=1 to 10000 do begin
    if not dfs(i) then break;
    inc(sum);
  end;
  writeln(sum-1);
end;

begin
  work;
end.

并查集,具体看hzwer大神,简直吓傻。

http://hzwer.com/2950.html

var
  chose:array[0..10002]of boolean;
  fa:array[0..10002]of longint;
  n,i,j,k,x1,x2:longint;

procedure swap(var x,y:longint);
var
  i:longint;
begin
  i:=x;
  x:=y;
  y:=i;
end;

function find(x:longint):longint;
begin
  if fa[x]<>x then fa[x]:=find(fa[x]);
  exit(fa[x]);
end;

begin
  readln(n);
  for i:=1 to 10002 do fa[i]:=i;
  for i:=1 to n do begin
    readln(j,k);
    x1:=find(j);
    x2:=find(k);
    if x1=x2 then chose[x1]:=true
      else begin
        if x1>x2 then swap(x1,x2);
        fa[x1]:=x2;
        chose[x1]:=true;
      end;
  end;
  for i:=1 to 10001 do
    if not chose[i] then begin
      writeln(i-1);
      break;
    end;
end.

速度上看差不多。

然后发几道残念!!根本不会写!!我去一定要找时间a掉。

3218: a + b Problem http://www.lydsy.com/JudgeOnline/problem.php?id=3218
2744: [HEOI2012]朋友圈 http://www.lydsy.com/JudgeOnline/problem.php?id=2744
1443: [JSOI2009]游戏Game http://www.lydsy.com/JudgeOnline/problem.php?id=1443
3035: 导弹防御塔http://www.lydsy.com/JudgeOnline/problem.php?id=3035

还有小学生oj若干题,再也不说小学生oj水了,好多题我不会啊啊啊啊!

这还怎么参加比赛。

时间: 2024-10-12 14:09:23

二分图的一些题目合集的相关文章

array题目合集

283. Move Zeroes 给定任意一个数组,把其中的0都移到该数组的末尾,其他的数字相对顺序要保持不变.例如:nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0]. 思路:不是0的往前赋值,同时用一个下标纪录当前赋值的数量,最后从这个下标开始赋值0即可. public class MoveZeroes { public void moveZeroes(int[] nums

二叉树题目合集

104. Maximum Depth of Binary Tree 找到二叉树的最大深度. public class Solution { public int maxDepth(TreeNode root) { if (root == null) { return 0; } int l = maxDepth(root.left) + 1; int r = maxDepth(root.right) + 1; return l > r ? l : r; } } 111. Minimum Depth

最长上升子序列(LIS)题目合集

有关最长上升子序列的详细算法解释在http://www.cnblogs.com/denghaiquan/p/6679952.html 1)51nod 1134 一题裸的最长上升子序列,由于N<=50000,n2算法会超时,只能用nlogn算法. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <string

sizeof题目合集

32位机器上定义如下结构体: struct xx{    long long _x1;    char _x2;    int _x3;    char _x4[2];    static int _x5;};int xx::_x5; 1-8的地址分给了_x1 , 9分给了_x2, 13-16分给了_x3,  int要按4对齐所以10-13的空间其实是浪费了 17-18分给了_x4, _x5不占用空类间, 最后本身是需要按照8对其 所以19-24也被占用了

openjudge1.6 题目合集(08~15)

08-石头剪刀布 #include<iostream> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[10001]; int b[10001]; int now_a[100001]; int now_b[100001]; int ying_a; int ying_b; int ping; int m

函数易错题目合集

var f1 = function f2(){}; f1.name //"f2" var f1 = function f2(){}; f2.name //报错:f2 is not defined var f1 = function f2(){}: console.log(f2) //f2 is not defined(f2 不存在,而且 f2 不是 undefined) function f(){console.log(this)}: f.call(1) //Number 对象 1 f

[题解+总结]动态规划大合集II

1.前言 大合集总共14道题,出自江哥之手(这就没什么好戏了),做得让人花枝乱颤.虽说大部分是NOIP难度,也有简单的几道题目,但是还是做的很辛苦,有几道题几乎没思路,下面一道道边看边分析一下. 2.lis 最长上升子序列 唯一一道裸题,但是O(n^2)过不了,临时看了看O(n log n)的二分做法和线段树做法.先来讲讲简单的二分做法,其本质就是在O(n^2)上进行优化,需要证明一个结论.设当前处理数列第k位,存在: (1)a[i]<a[j]<a[k]: (2)i<j<k: (3

[知识点]NOIP动态规划大合集

1.前言 NOIP2003-2014动态规划题目大合集,有简单的也有难的(对于我这种动态规划盲当然存在难的),今天就把这些东西归纳一下,做一个比较全面的总结,方便对动态规划有一个更深的理解. 2.NOIP2003 加分二叉树 树形DP入门题,根据题意,一个树的加分=左子树*右子树+根节点,由此可以设f[i][j]为子树i到j的加分,则有方程:f[i][j]=max{d[t]+f[i,t-1]*f[t+1,j]} ( t∈[i,j] ) 3.NOIP2004 合唱队形 应该是最简单的一道了,枚举队

机器学习和深度学习资料合集

机器学习和深度学习资料合集 注:机器学习资料篇目一共500条,篇目二开始更新 希望转载的朋友,你可以不用联系我.但是一定要保留原文链接,因为这个项目还在继续也在不定期更新.希望看到文章的朋友能够学到更多.此外:某些资料在中国访问需要梯子. <Brief History of Machine Learning> 介绍:这是一篇介绍机器学习历史的文章,介绍很全面,从感知机.神经网络.决策树.SVM.Adaboost到随机森林.Deep Learning. <Deep Learning in