1.最小覆盖(最大匹配模板)
(n*n)个图 k个边 求最小覆盖数
#include <stdio.h>
#include<string.h>
#include<algorithm>
#define N 1001
using namespace std;
int useif[N]; //记录y中节点是否使用 0表示没有访问过,1为访问过
int link[N]; //记录当前与y节点相连的x的节点
int mat[N][N]; //记录连接x和y的边,如果i和j之间有边则为1,否则为0
int gn,gm; //二分图中x和y中点的数目
int can(int t)
{
int i;
for(i=1;i<=gm;i++)
{
if(useif[i]==0 && mat[t][i])
{
useif[i]=1;
if(link[i]==-1 || can(link[i]))
{
link[i]=t;
return 1;
}
}
}
return 0;
}
int MaxMatch()
{
int i,num;
num=0;
memset(link,0xff,sizeof(link));
for(i=1;i<=gn;i++)
{
memset(useif,0,sizeof(useif));
if(can(i)) num++;
}
return num;
}
int main(int argc, char *argv[])
{
int n,k;
while(scanf("%d %d",&n,&k)!=EOF)
{
gn=gm=n;
while(k--)
{
int c,d;
scanf("%d %d",&c,&d);
mat[c][d]=1;
}
printf("%d\n",MaxMatch());
}
return 0;
}
2.KM() 完美匹配 n*n 个边求收益最大的匹配
#include <iostream>
#include <cstring>
#include <cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 305;
const int INF = 0x3f3f3f3f;
int love[MAXN][MAXN]; // 记录每个妹子和每个男生的好感度
int ex_girl[MAXN]; // 每个妹子的期望值
int ex_boy[MAXN]; // 每个男生的期望值
bool vis_girl[MAXN]; // 记录每一轮匹配匹配过的女生
bool vis_boy[MAXN]; // 记录每一轮匹配匹配过的男生
int match[MAXN]; // 记录每个男生匹配到的妹子 如果没有则为-1
int slack[MAXN]; // 记录每个汉子如果能被妹子倾心最少还需要多少期望值
int N;
bool dfs(int girl)
{
vis_girl[girl] = true;
for (int boy = 0; boy < N; ++boy) {
if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次
int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];
if (gap == 0) { // 如果符合要求
vis_boy[boy] = true;
if (match[boy] == -1 || dfs( match[boy] )) { // 找到一个没有匹配的男生 或者该男生的妹子可以找到其他人
match[boy] = girl;
return true;
}
} else {
slack[boy] = min(slack[boy], gap); // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸
}
}
return false;
}
int KM()
{
memset(match, -1, sizeof match); // 初始每个男生都没有匹配的女生
memset(ex_boy, 0, sizeof ex_boy); // 初始每个男生的期望值为0
// 每个女生的初始期望值是与她相连的男生最大的好感度
for (int i = 0; i < N; ++i) {
ex_girl[i] = love[i][0];
for (int j = 1; j < N; ++j) {
ex_girl[i] = max(ex_girl[i], love[i][j]);
}
}
// 尝试为每一个女生解决归宿问题
for (int i = 0; i < N; ++i) {
fill(slack, slack + N, INF); // 因为要取最小值 初始化为无穷大
while (1) {
// 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止
// 记录每轮匹配中男生女生是否被尝试匹配过
memset(vis_girl, false, sizeof vis_girl);
memset(vis_boy, false, sizeof vis_boy);
if (dfs(i)) break; // 找到归宿 退出
// 如果不能找到 就降低期望值
// 最小可降低的期望值
int d = INF;
for (int j = 0; j < N; ++j)
if (!vis_boy[j]) d = min(d, slack[j]);
for (int j = 0; j < N; ++j) {
// 所有访问过的女生降低期望值
if (vis_girl[j]) ex_girl[j] -= d;
// 所有访问过的男生增加期望值
if (vis_boy[j]) ex_boy[j] += d;
// 没有访问过的boy 因为girl们的期望值降低,距离得到女生倾心又进了一步!
else slack[j] -= d;
}
}
}
// 匹配完成 求出所有配对的好感度的和
int res = 0;
for (int i = 0; i < N; ++i)
res += love[ match[i] ][i];
return res;
}
int main()
{
while(scanf("%d",&N)!=EOF)
{
int i,j;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
scanf("%d",&love[i][j]);
}
}
printf("%d\n",KM());
}
return 0;
}
3.模拟链表(从小到达插入一个数)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int a[105];
int main() {
int data[101],right[101];
int n,t,len,x;
scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&data[i]);
len=n;
//初始化数组right
for(int i=1; i<=n; i++) {
if(i!=n) right[i]=i+1;
else right[i]=0;
}
//直接在数组data的末尾增加一个数x,也就是data[len]
len++;
scanf("%d",&data[len]);
//从链表头部开始遍历
if(data[len]>=data[1] && data[len]<=data[len-1]) {
t=1;
while(t!=0) {
if(data[right[t]]>data[len]) { //当发现第一个大于x的结点时,就说明x应该插入到这个数前面
right[len]=right[t];//将x后面的结点设为第一个大于x的结点
right[t]=len;//将一个大于x的结点前面的结点的下一个结点设为x
break;
}
t=right[t];
}
}
else if(data[len]<data[1]) cout<<data[len]<<" ";
//输出链表的所有数
t=1;
while(t!=0) {
printf("%d ",data[t]);
t=right[t];
}
if(data[len]>data[len-1]) cout<<data[len];
return 0;
}
4.Floyd+路径输出(求多源最短路)
#include <stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define inf 0x00ffffff
int map[200][200];
int path[200][200];
int tax[200];
int main(int argc, char *argv[])
{
int n;
while(scanf("%d",&n),n)
{
memset(path,0,sizeof(path));
int i,j,k;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&map[i][j]);
if(map[i][j]!=-1)
path[i][j]=j;
else
map[i][j]=inf;
}
}
for(i=1;i<=n;i++)
scanf("%d",&tax[i]);
for(k=1;k<=n;k++)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(map[i][j]>map[i][k]+map[k][j]+tax[k])
{
path[i][j]=path[i][k];
map[i][j]=map[i][k]+map[k][j]+tax[k];
}
else if(map[i][j]==(map[i][k]+map[k][j]+tax[k]))
{
if(path[i][j]>path[i][k])
{
path[i][j]=path[i][k];
map[i][j]=map[i][k]+map[k][j]+tax[k];
}
}
}
}
}
int start,end;
while(scanf("%d %d",&start,&end)!=EOF)
{
if(start==-1&&end==-1)
break;
printf("From %d to %d :\n",start,end);
printf("Path: %d",start);
int next=start;
while(next!=end)
{
printf("-->%d",path[next][end]);
next=path[next][end];
}
printf("\n",end);
printf("Total cost : %d\n\n",map[start][end]);
}
}
return 0;
}
5.Floyd(最小环)
#include <stdio.h>
#define inf 99999999
#include<algorithm>
using namespace std;
int map[101][101];
int dis[101][101];
int main(int argc, char *argv[])
{
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{
int i,j,k;
for(i=0;i<=n;i++)
{
for(j=0;j<=n;j++)
{
map[i][j]=map[j][i]=dis[i][j]=dis[j][i]=inf;
}
}
while(m--)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
map[a][b]=map[b][a]=dis[a][b]=dis[b][a]=min(map[a][b],c);
}
int min1=inf;
for(k=1;k<=n;k++)
{
for(i=1;i<k;i++)
{
for(j=i+1;j<k;j++)
{
min1=min(min1,map[i][k]+map[k][j]+dis[i][j]);
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
if(min1>=inf)
{
printf("It's impossible.\n");
}
else
printf("%d\n",min1);
}
return 0;
}
6.给出一个图,要求出最大的pseudoforest, 所谓pseudoforest就是指这个图的一个子图,这个子图的每个连通分量中最多只能有一个环, 而且这个子图的所有权值之和最大。这个就是所谓的伪森林。
#include <stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int bin[100010],flag;
long long sum;
struct node{
int s,e,w;
}a[100001];
int judge[100001];
int findx(int x)
{
return bin[x]==x?x:bin[x]=findx(bin[x]);
}
int merge(int a,int b,int c)
{
int fx=findx(a);
int fy=findx(b);
if(fx!=fy)
{
if(judge[fx]&&judge[fy])
return 0;
bin[fy]=fx;
sum+=c;
if(judge[fx]||judge[fy])
judge[fx]=1;
}
else if(fx==fy&&!judge[fx])
{
judge[fx]=1;
sum+=c;
}
}
int cmp(node a,node b)
{
return a.w>b.w;
}
int main(int argc, char *argv[])
{
int n,m;
while(scanf("%d %d",&n,&m),m+n)
{
int i;
memset(judge,0,sizeof(judge));
for(i=0;i<n;i++)
{
bin[i]=i;
}
for(i=0;i<m;i++)
{
scanf("%d %d %d",&a[i].s,&a[i].e,&a[i].w);
}
sort(a,a+m,cmp);
sum=0;
for(i=0;i<m;i++)
{
merge(a[i].s,a[i].e,a[i].w);
}
printf("%lld\n",sum);
}
return 0;
}