bzoj 4443
首先很容易看出这是一个需要使用二分的二分图,要选出第K大的数,即找到第n-k+1小的数,对于题目中的两个数字不能在同一行或同一列,这是一个在二分图题目中常见的条件,对应的解决方法就是使用行列建边
所以最后的过程是首先我们二分出一个值,对于小于等于这个值的数,进行行列建图,最后判断匹配数是否为n-k+1即可
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=65000;
const int maxm=maxn*2;
struct Node
{
int to;
int next;
}edge[maxm];
int cnt;
int n,m,k;
int head[maxn];
int map[310][310];
int match[maxn];
bool vis[maxn];
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
return;
}
void add(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
return;
}
void build(int mid)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(map[i][j]<=mid)
{
add(i,j+n);
}
}
}
return;
}
bool dfs(int node)
{
for(int i=head[node];~i;i=edge[i].next)
{
int v=edge[i].to;
if(!vis[v])
{
vis[v]=true;
if(match[v]==-1||dfs(match[v]))
{
match[v]=node;
return true;
}
}
}
return false;
}
int hungry()
{
int ans=0;
memset(match,-1,sizeof(match));
for(int i=1;i<=n;i++)
{
memset(vis,false,sizeof(vis));
if(dfs(i))
{
ans++;
}
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%d%d",&n,&m,&k))
{
int minn=0x3f3f3f3f;
int maxx=-1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&map[i][j]);
minn=min(minn,map[i][j]);
maxx=max(maxx,map[i][j]);
}
}
int left=minn;
int right=maxx;
while(left<=right)
{
int mid=(left+right)>>1;
init();
build(mid);
int res=hungry();
if(res>=n-k+1)
{
right=mid-1;
}
else
{
left=mid+1;
}
}
cout<<left<<endl;
}
return 0;
}
HDU 1596
dijkstra变形,很多人都写出来了,不多说,注意浮点数就好了
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1010;
//const double inf=0x3f3f3f3f+0.5;
int n;
double map[maxn][maxn];
double dis[maxn];
bool book[maxn];
void dijkstra(int start,int end)
{
memset(book,false,sizeof(book));
for(int i=1;i<=n;i++) dis[i]=map[start][i];
book[start]=true;
dis[start]=1;
for(int i=1;i<=n;i++)
{
double minn=0;
int flag=start;
for(int j=1;j<=n;j++)
{
if(!book[j]&&dis[j]>minn)
{
minn=dis[j];
flag=j;
}
}
if(flag==end) break;
book[flag]=true;
for(int j=1;j<=n;j++)
{
if(!book[j]&&dis[j]<dis[flag]*map[flag][j]){
dis[j]=dis[flag]*map[flag][j];
}
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%lf",&map[i][j]);
}
}
int q;
scanf("%d",&q);
for(int i=0;i<q;i++)
{
int start,end;
scanf("%d%d",&start,&end);
dijkstra(start,end);
if(dis[end]==0) printf("What a pity!\n");
else printf("%.3f\n",dis[end]);
}
}
}
HDU 6290
博客链接:https://www.cnblogs.com/luoxiaoyi/p/9726829.html
HDU 6187
其实是一道很好想的题,如果国王要去别的地方,那么肯定不能出现环把它围住,又要求拆除边数总权值最少,求个最大生成树即可
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e5+7;
const int maxm=2e5+7;
struct Node
{
int u,v,w;
}edge[maxm];
int tree[maxn];
bool cmp(Node a,Node b)
{
return a.w>b.w;
}
int find(int node)
{
return tree[node]==node?node:tree[node]=find(tree[node]);
}
int main()
{
//freopen("in.txt","r",stdin);
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
tree[i]=i;
}
int sum=0;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
sum+=edge[i].w;
}
sort(edge,edge+m,cmp);
int cnt=0;
int ans=0;
for(int i=0;i<m;i++)
{
int x=find(edge[i].u);
int y=find(edge[i].v);
if(x!=y)
{
tree[x]=y;
ans+=edge[i].w;
cnt++;
}
}
cout<<m-cnt<<' '<<sum-ans<<endl;
}
return 0;
}
HDU 2819
二分图匹配
根据线性代数的知识,对于一个单位矩阵,它的秩为n。任意交换矩阵的两行或两列,矩阵的秩是不会改变的。所以如果通过行变换无法使这个矩阵变为单位矩阵,那么通过列变换一定也不行。
那么我们通过行和列来构建这个二分图,对于任意的
1
≤
i
≤
n
1\leq i \leq n
1≤i≤n,若num[i][j]为1,那么就让i与j连一条边,就表示第j列可以移动到第i行的第i列
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
const int maxm=1e5+7;
struct Node
{
int to;
int next;
}edge[maxm];
int cnt;
int head[maxn];
int num[110][110];
bool vis[maxn];
int match[maxn];
int n;
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
return;
}
void add(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
return;
}
int dfs(int node)
{
for(int i=head[node];~i;i=edge[i].next)
{
int v=edge[i].to;
if(!vis[v])
{
vis[v]=true;
if(match[v]==-1||dfs(match[v]))
{
match[v]=node;
return true;
}
}
}
return false;
}
int hungry()
{
int ans=0;
memset(match,-1,sizeof(match));
for(int i=1;i<=n;i++)
{
memset(vis,false,sizeof(vis));
if(dfs(i))
{
ans++;
}
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d",&n))
{
init();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&num[i][j]);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(num[i][j])
{
add(i,j);
}
}
}
int res=hungry();
if(res<n)
{
puts("-1");
}
else
{
vector<pair<int,int> > vec;
for(int i=1;i<=n;i++)
{
if(match[i]==i) continue;
//if(match[i]==-1) continue;
for(int j=1;j<=n;j++)
{
if(i==j) continue;
if(match[j]==i)
{
vec.push_back(make_pair(i,j));
swap(match[i],match[j]);
//match[j]=match[i]=-1;
}
}
}
int len=vec.size();
cout<<len<<endl;
for(int i=0;i<len;i++)
{
cout<<"C "<<vec[i].first<<' '<<vec[i].second<<endl;
}
}
}
return 0;
}
/*
3
0 0 1
1 0 0
0 1 0
*/
HDU 1102
最小生成树的模板题,不多说
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=110;
const int inf=0x3f3f3f3f;
int map[maxn][maxn];
int dis[maxn];
bool book[maxn];
int n;
int prim()
{
memset(book,false,sizeof(book));
for(int i=1;i<=n;i++) dis[i]=map[1][i];
for(int i=0;i<n;i++)
{
int minn=inf;
int flag=1;
for(int j=1;j<=n;j++)
{
if(!book[j]&&dis[j]<minn){
minn=dis[j];
flag=j;
}
}
book[flag]=true;
for(int j=1;j<=n;j++)
{
if(!book[j]&&dis[j]>map[flag][j])
{
dis[j]=map[flag][j];
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
ans+=dis[i];
}
return ans;
}
int main()
{
while(cin>>n)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>map[i][j];
}
}
int m;
cin>>m;
while(m--)
{
int a,b;
cin>>a>>b;
map[a][b]=map[b][a]=0;
}
cout<<prim()<<endl;
}
}
bzoj 1050
https://blog.youkuaiyun.com/clove_unique/article/details/52612011
CodeForces 989C
https://blog.youkuaiyun.com/I_believe_CWJ/article/details/80660869