#include <iostream>
using namespace std;
const int MAXN=100005;
string a[MAXN];
//这里不定义二维数组以防止数组过大
int n,m;
int flag=0;
int px[]={1,0,-1,0},py[]={0,1,0,-1};
//格子控制左上右下移动
//dfs递归
void dfs(int i,int j)
{
if(i<0||i>=n||j<0||j>=m||a[i][j]=='0')return;
//该点不是1,或者i,j超出边界
if(a[i][j]>'1')flag=1;//是宝藏
a[i][j]='0';
//置该点为0
for(int k=0;k<4;k++)dfs(i+px[k],j+py[k]);
//向各个方向延申
}
int main()
{
int c=0,cnt=0;
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(a[i][j]>'0'){
c=c+1;
flag=0;
dfs(i,j);
if(flag)cnt++;
}
}
}
cout<<c<<" "<<cnt<<endl;
}
7-4 最小生成树-Prim算法(从任意顶点开始)
复制代码
#include<bits/stdc++.h>
using namespace std;
int inf=0x3f3f3f3f;
int graph[10000][10000]={0};
int lowcost[10000]={0};//点集
int tree[10000]={0};
int m,n,ls;
void prim(int s)
{
for(int i=1;i<=n;i++)
{
if(i==s)
lowcost[i]=0;
else
lowcost[i]=graph[s][i];
tree[i]=s;//初始化,所有的边都待选
}
int minn,pos;
for(int i=1;i<n;i++)//循环了n-1次,因为n个点,n-1个边
{
minn=inf;
for(int j=1;j<=n;j++)
{
if(lowcost[j]!=0&&lowcost[j]<minn)
{
minn=lowcost[j];
pos=j;
}//这个找的就是点集周围的最小边
}
cout<<(tree[pos]<pos?tree[pos]:pos)<<","<<(tree[pos]>pos?tree[pos]:pos)<<","<<graph[tree[pos]][pos]<<endl;//每找到一个边就输出一个边
if(minn==inf)
break;
lowcost[pos]=0;//加入!!
for(int j=1;j<=n;j++)
{
if(lowcost[j]!=0&&graph[pos][j]<lowcost[j])//因为没在点集里,s到j比较大,pos到j小,就更新一下
{
lowcost[j]=graph[pos][j];//其实就是点集到j最短的距离
tree[j]=pos;//加入到tree的待选,下次循环会选出来合适的,到时候这里的j会是合适的pos,这里的pos对应上一次合适的值。
}
}
}
}
int main()
{
cin>>n>>m>>ls;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
graph[i][j]=inf;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
cin>>graph[a][b];
graph[b][a]=graph[a][b];
}
prim(ls);
}
7-5 h0359. 并查集
复制代码
#include <iostream>
#include <vector>
using namespace std;
vector<int> parent;
int find(int x) {
if (parent[x] == x) {
return x;
} else {
return parent[x] = find(parent[x]);
}
}
void merge(int a, int b) {
int rootA = find(a);
int rootB = find(b);
if (rootA != rootB) {
parent[rootB] = rootA;
}
}
int main() {
int n, m;
cin >> n >> m;
// 初始化并查集
parent.resize(n + 1);
for (int i = 1; i <= n; ++i) {
parent[i] = i;
}
char op;
int a, b;
for (int i = 0; i < m; ++i) {
cin >> op >> a >> b;
if (op == 'M') {
merge(a, b);
} else if (op == 'Q') {
if (find(a) == find(b)) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
}
return 0;
}
7-6 h0360. 并查集2
复制代码
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int p[N], cnt[N];
int find(int x) {
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++ ) p[i] = i, cnt[i] = 1;
while(m -- ) {
char op[3];
int a, b;
scanf("%s", op);
if(op[0] == 'C') {
scanf("%d%d", &a, &b);
if(find(a) == find(b)) continue;
cnt[find(b)] += cnt[find(a)];
p[find(a)] = find(b);
} else if(op[1] == '1') {
scanf("%d%d", &a, &b);
if(find(a) == find(b)) printf("Yes\n");
else printf("No\n");
} else {
scanf("%d", &a);
printf("%d\n", cnt[find(a)]);
}
}
return 0;
}
7-7 h0361. 并查集3
复制代码
#include<iostream>
#include<cstdio>
using namespace std;
int pre[50003],rel[50003];
int f(int x){
if(x==pre[x])return x;
int tmp=pre[x];
pre[x]=f(pre[x]);
rel[x]=(rel[x]+rel[tmp])%3;
return pre[x];
}
int link(int x,int y,int flag){
int root1=f(x),root2=f(y);
if(root1==root2){//表示已经合并啦
if(flag!=(3-rel[x]+rel[y])%3)return 0;
else return 1;
}
pre[root2]=root1;
rel[root2]=(rel[x]+flag+3-rel[y])%3;
return 1;
}
int main(){
int n,k,flag,x,y;
scanf("%d%d",&n,&k);
int ans=0;
for(int i=1;i<=n;i++){
pre[i]=i;
rel[i]=0;
}
while(k--){
scanf("%d%d%d",&flag,&x,&y);
if(x>n||y>n){ans++;continue;}
if(flag==2&&x==y){ans++;continue;}
if(!link(x,y,flag-1))ans++;
}
printf("%d\n",ans);
}
7-8 吉利矩阵
复制代码
#include<iostream>
using namespace std;
const int N=20;
int a[N][N];
int main(){
int l,n;cin>>l>>n;
a[2][2]=3;
a[2][3]=21;
a[2][4]=282;
a[3][2]=4;
a[3][3]=55;
a[3][4]=2008;
a[4][2]=5;
a[4][3]=120;
a[4][4]=10147;
a[5][2]=6;
a[5][3]=231;
a[5][4]=40176;
a[6][2]=7;
a[6][3]=406;
a[6][4]=132724;
a[7][2]=8;
a[7][3]=666;
a[7][4]=381424;
a[8][2]=9;
a[8][3]=1035;
a[8][4]=981541;
a[9][2]=10;
a[9][3]=1540;
a[9][4]=2309384;
cout<<a[l][n];
}
7-9 最小费用流
复制代码
#include <iostream>
#include <vector>
#include <queue>
#include <limits>
using namespace std;
const int INF = numeric_limits<int>::max();
struct Edge {
int to, cap, cost, rev;
};
vector<vector<Edge>> graph;
vector<int> dist;
vector<int> prevv, preve;
void add_edge(int from, int to, int cap, int cost) {
graph[from].push_back(Edge{to, cap, cost, static_cast<int>(graph[to].size())});
graph[to].push_back(Edge{from, 0, -cost, static_cast<int>(graph[from].size()) - 1});
}
pair<int, int> min_cost_flow(int s, int t) {
int flow = 0, cost = 0;
while (true) {
queue<int> que;
dist.assign(graph.size(), INF);
dist[s] = 0;
que.push(s);
while (!que.empty()) {
int v = que.front();
que.pop();
for (int i = 0; i < graph[v].size(); ++i) {
Edge &e = graph[v][i];
if (e.cap > 0 && dist[e.to] > dist[v] + e.cost) {
dist[e.to] = dist[v] + e.cost;
prevv[e.to] = v;
preve[e.to] = i;
que.push(e.to);
}
}
}
if (dist[t] == INF) {
break;
}
int d = INF;
for (int v = t; v != s; v = prevv[v]) {
d = min(d, graph[prevv[v]][preve[v]].cap);
}
flow += d;
cost += d * dist[t];
for (int v = t; v != s; v = prevv[v]) {
Edge &e = graph[prevv[v]][preve[v]];
e.cap -= d;
graph[v][e.rev].cap += d;
}
}
return make_pair(flow, cost);
}
int main() {
int n, m;
cin >> n >> m;
graph.resize(n + 1);
dist.resize(n + 1);
prevv.resize(n + 1);
preve.resize(n + 1);
for (int i = 0; i < m; ++i) {
int s, t, c, w;
cin >> s >> t >> c >> w;
add_edge(s, t, c, w);
}
pair<int, int> result = min_cost_flow(1, n);
cout << result.first << " " << result.second << endl;
return 0;
}