您的位置:首页 > 其它

18-1-30~2~5一周算法总结(DP,二分图,最小生成树)

2018-02-05 16:57 417 查看
30

DP(最长上升子序列和lcs)

摸了

1

DP(01背包和完全背包)

01背包

for(int i=1;i<=n;i++){
for(int j=k;j>=w[i];j--){
dp[j]=max(dp[j-w[i]]+v[i],dp[j]);//维护对于第i个物品,不放的时候的最大值和放了之后空间减少w[i]的最大值
}
}
完全背包和01背包基本一致,唯一的区别是从01是逆推但是完全是顺推(顺推就可以在已经放了本物品的基础上再次放)

for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
if(j>=w[i]){
dp[j]=min(dp[j],dp[j-w[i]]+v[i]);
}
}
}
对于那种可以在最后的空间插入更大的值的问题,可以一上来就把空间j的大小减x来达到。

3

二分图

2点,一个是区分是否二分图,一个是算二分图的最多匹配数。

是否二分可以很简单的用染色来判断。bfs遍历。

算匹配数用到匈牙利算法。核心代码如下。

邻接矩阵

int n,m;
int line[1000+5][1000+5],used[1000+5],nxt[1000+5] ;

bool Find(int x){
for(int i=1;i<=m;i++){
if(line[x][i]&&!used[i]){
used[i]=1;
if(nxt[i]==0||Find(nxt[i])){
nxt[i]=x;
return true;
}
}
}
return false;
}

int match(){
int all=0;
for(int i=1;i<=n;i++){
mem(used,0);
if(Find(i)) all++;
}
return all;
}
邻接表

下次再补

PS:还有需要注意的一些细节

 1最大不相关个数=总个数-最大匹配个数

 2如果没有专门给你区分x来着左,y来自右,那么可以在构建的时候line[x][y]=1,line[y][x]=1,但是这样的话

最大匹配=match()/2;
 3其实给我们一个有向图,在做与1内容相关的题目的时候,我们可以近似的看成是无向图,不过是出发点是左,
终点是右,来计算。(也不是很懂,但是可以做)poj 1422
4最大匹配个数=(覆盖图的)最小顶点个数

5

最小生成树

需要并查集。

其次基本思想是套用kruskal算法,将边的花费保存,并按从小到大打排序,依次取出边,如果边的2个端点没有通路,则把这2个端点用这条边连起来。

代码

const int maxn=1e5+5;
int f[maxn];
struct edge{
int x,y,cost;
} e[10005];
//int  rank[maxn];
void init(){//初始化//
for(int i=1;i<maxn;i++){
f[i]=i;
//		rank[i]=0;
}
}

int find(int x){//查找并优化到这条链上的所以结点都和根直接相连//
return f[x]==x?x:f[x]=find(f[x]);
}

void un(int x,int y){//连点// 未用rank优化,取消掉/则转变为rank优化//
int a=find(x);
int b=find(y);
if(a!=b){
//		if(rank[a]>rank)
f[b]=a;
/*		else{
f[a]=b;
if(rank[a]==rank[b])
rank[a]++;
}*/
}
}

bool cmp(edge e1,edge e2){
return e1.cost<e2.cost;
}

int kruskal(){
init();
sort(e,e+m,cmp);
int all=0;
for(int i=0;i<m;i++){
int x=e[i].x;
int y=e[i].y;
if(find(x)==find(y)) continue;
un(x,y);
all+=e[i].cost;
}
return all;
}
PS:我这里是返回了最小生成树的边的长度。
[b]非课程相关


突然知道的,


ll超过范围会自动取模啊,ull也是!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: