口胡一段:2333说好要坚持写博客结果上一条是一个月以前,第五次上机预感会很难(大概因为第四次真的有点送分),所以先写一篇押题+部分原理讲解的博客。
主要分为:贪心——活动安排问题;DP——逆推+概率+多路;二分图匹配以及最大流问题,及其经典代表题(目标两天刷30道的节奏)有些有意思但是没什么太大关系的我也会瞎BB一部分。
因为时间仓促,难免会有疏漏之处,敬请指正!
First Blood!贪心—活动安排问题
#include <bits/stdc++.h>
struct node{
int start;
int end;
int flag;
};
bool cmp(node x,node y)
{
return x.end<y.end;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF) //number of activity
{
node a[n+2];
for(int i=0;i<n;i++)
{
scanf("%d%d",&a[i].start,&a[i].end);
a[i].flag=0;
}
std::sort(a,a+n,cmp);
int sum=0,lastend=0;
if(a[0].end!=0)
{
lastend=a[0].end;
sum++;
a[0].flag=1;
}
for(int i=1;i<n;i++)
{
if(a[i].start>=lastend)
{
lastend=a[i].end;
sum++;
a[i].flag=1;
}
}
printf("%d\n",sum);
printf("所取活动分别为:\n");
for(int i=0;i<n;i++)
{
if(a[i].flag==1)
printf("(%d,%d)\n",a[i].start,a[i].end);
}
}
}
经典例题:HDU2037 今年暑假不AC 板子题,就不上代码了。(HDU编译不了bits/stdc++.h)
2 活动安排plus
有若干个活动,第i个开始时间和结束时间是(S,E),活动之间不能交叠,要把活动都安排完,至少需要几个教室?
与经典不同:要求所有活动均被安排,决定教室个数的是开始时间与结束时间的冲突个数。故在此问题中,需要遍历开始时间数组,若大于等于该教室最早结束时间,并入教室,否则单开教室,所有存在教室均应被遍历。
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct node{
int start;
int end;
};
bool cmp(node x,node y)
{
return x.start<y.start;
}
int main()
{
int n;
while(cin>>n)
{
node a[n+2];
for(int i=0;i<n;i++)
{
cin>>a[i].start>>a[i].end;
}
sort(a,a+n,cmp);
int classroom[n+2];//该数组下标记录有几个教室,数值记录该教师最早结束时间
memset(classroom,0,sizeof(classroom));
int number=0,mark=0;
classroom[0]=a[0].end;
for(int i=1;i<n;i++)
{
mark=0;
for(int j=0;j<=number;j++)
{
if(a[i].start>=classroom[j])
{
classroom[j]=a[i].end;
mark=1;
break;
}
}
if (mark == 0)
{
number++;
classroom[number]=a[i].end;
}
}
cout<<number+1<<endl;
}
}
Double Kill!DP问题
概率DP和逆推DP的区别:一般地,求概率是正推、求期望是逆推。因为若是求概率,一般基本事件的概率都是确定的,可以采用正推;而若是期望,每一步都是不可预测的,需要从结尾逆推回起点。
#include <iostream>
#include <cstring>
using namespace std;
double dp[1003][1003];
//dp[i][j];/dp[n][s] i bug j system
//dp[i][j] 在已有bug的系统中发现已经被发现过的bug类型
//int p1=i*j/n*s;
//dp[i+1][j] 在已有bug的系统中发现新bug类型
//int p2=(n-i)*j/n*s;
//dp[i][j+1] 在新系统中发现已经被发现过的bug类型
//int p3=i*(s-j)/n*s;
//dp[i+1][j+1] 在新系统中发现新bug类型
//int p4=(n-i)*(s-j)/n*s;
int main()
{
int n,s;
while(cin>>n>>s)
{
memset(dp,0,sizeof(dp));
for(int i=n;i>=0;i--)
{
for(int j=s;j>=0;j--)
{
if(i==n&&j==s) continue;//注意此处的条件判断!!
double p1=(n*s-i*j)*1.0;
double p2=(n-i)*j*1.0;
double p3=i*(s-j*1.0);
double p4=(n-i)*(s-j)*1.0;
dp[i][j]=(p2*dp[i+1][j]+p3*dp[i][j+1]+p4*dp[i+1][j+1]+n*s)/p1;
}
}
printf("%.4lf\n",dp[0][0]);
}
}
2 概率DP
#include <iostream>
#include <cstring>
using namespace std;
double dp[155][155],p[155][155];
//do[i][j]表示在第i轮比赛中j队获胜的概率
//注意初始化边界:在第0轮比赛中,每支队伍获胜的概率均为1
int main()
{
int n;//有几轮比赛
while(cin>>n)
{
if(n==-1) break;
int num;//队伍总数
num=1<<n;
memset(dp,0,sizeof(dp));
for(int i=0;i<num;++i)
dp[0][i]=1;
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
cin>>p[i][j];
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<num;j++)
{
for(int k=0;k<num;k++)
{
if((j>>(i-1))==((k>>(i-1))^1)) //保证j队和k队是第一次进行比赛
dp[i][j]+=dp[i-1][j]*dp[i-1][k]*p[j][k];//j,k两队均需要在第i-1轮比赛中获胜,p[j][k]表示j队击败k队的概率
}
}
}
int ans=0;
for(int i=1;i<num;i++)
{
if(dp[n][i]>dp[n][ans]) ans=i;
}
cout<<ans+1<<endl;
}
}
Triple Kill!二分图问题
最大匹配数:最大匹配的匹配边的数目
最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择
最大独立数:选取最多的点,使任意所选两点均不相连
最小路径覆盖数:对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。
定理1:最大匹配数 = 最小点覆盖数(这是 Konig 定理)
定理2:最大匹配数 = 最大独立数
定理3:最小路径覆盖数 = 顶点数 - 最大匹配数
例题:POJ 3041
求最小点覆盖数,运用定理1,转化为求最大匹配数问题。板子题。
匈牙利算法求解的是最大匹配问题,还有一类完全匹配问题,实质上是判定。在无权图中只要节点数/2==匹配数即可。
补充:二分图匹配中有Hopcroft-Karp算法,基于最大流思想,比较复杂,类似于最大流中Dinic算法。是目前已知的最快的解决二分图匹配的算法。
https://www.cnblogs.com/crazyac/articles/1917278.html 真TM难啊。
可以参考1973年算法两位作者的论文:《Algorithm for Maximum Matchings in Bipartite Graphs》,发表于SIAM J. Computing
例题:buaacoding 570 二营长,你他娘的意大利炮呢(这题名太有意思了忍不住帮学长安利一发)实际上是脱胎于POJ 3041
二分图匹配之二分图的判定
难题先略过,明白二分图问题中最主要的匹配算法的思想后,看一些相关问题。先看这个简单的判定问题,嗯我的意思是后面的那个KM算法是玄学。
判定思路:使用染色法。遍历其中一个维度的节点,与其相连的节点染色情况会有以下三种
1 未染色:将其染上与本节点不同的色即可
2 已染色但是颜色与本节点相同:非二分图
3 已染色且颜色与本节点不同:跳过该节点
可以看出算法和匈牙利算法是很相似的,不在此处粘贴代码了。
二分图匹配之带权二分图最大匹配
说实话,不会……甩链接:https://www.cnblogs.com/kuangbin/archive/2012/08/19/2646535.html
Quadra Kill!最大流问题
现行主要有4个算法:Ford-Fulkerson(效率比较低);Edmonds-Karp(基于BFS);Dinic(基于BFS);SAP(难!慎!)
为什么最难的最大流东西这么少:因为真的写不完这篇博客了啊啊马上就要上机了还没刷题