2023.7.26 结题报告
2023.7.26 DAY3
T1
搜索题,考试的时候没想出来正解,所以乱搞了一下,把没有匹配上的点给取出来然后枚举取最小值,30pts。
#include<bits/stdc++.h>
#define int long long
#define N 20
using namespace std;
int ans, X1[N], Y1[N], top1, X2[N], Y2[N], top2, vis[N];
char mp1[N][N], mp2[N][N];
signed main()
{
for(int i = 1; i <= 4; i ++)
for(int j = 1; j <= 4; j ++)
cin >> mp1[i][j];
for(int i = 1; i <= 4; i ++)
{
for(int j = 1; j <= 4; j ++)
{
cin >> mp2[i][j];
if(mp1[i][j] == '1' && mp2[i][j] == '1') mp1[i][j] = mp2[i][j] = '0';
if(mp1[i][j] == '0' && mp2[i][j] == '1') X2[++ top2] = i, Y2[top2] = j;
if(mp1[i][j] == '1' && mp2[i][j] == '0') X1[++ top1] = i, Y1[top1] = j;
}
}
// cout << X2[1] << " " << Y2[1] << endl;
for(int i = top1; i >= 1; i --)
{
int k = 0, minn = 1e9;
for(int j = top2; j >= 1; j --)
{
if(vis[j]) continue;
int res = abs(X1[i] - X2[j]) + abs(Y1[i] - Y2[j]);
if(res < minn) k = j, minn = res;
}
ans += minn;
vis[k] = 1;
}
cout << ans << endl;
// cout << top1 << " " << top2 << endl;
return 0;
}
/*
0001
0000
0010
0100
0010
1000
0001
0000
5
*/
期间我也打了一个广搜的代码,但是打挂了,我以为暴力不是正解,所以开始想别的,
#include <bits/stdc++.h>
#define int long long
#define N 11
using namespace std;
int dx[] = {0, 0, 0, 1, -1,};
int dy[] = {0, 1, -1, 0, 0,};
int vis[N][N], ans, k, dis[N][N];
char mp1[N][N], mp2[N][N];
inline void bfs(int X, int Y)
{
queue <int> qx, qy;
qx.push(X), qy.push(Y);
while(!qx.empty())
{
int x = qx.front(); qx.pop();
int y = qy.front(); qy.pop();
for(int i = 1; i <= 4; i ++)
{
int xx = x + dx[i];
int yy = y + dy[i];
if(vis[xx][yy] == 0)
{
if(mp2[xx][yy] == '1')
{
mp1[xx][yy] = '1';
mp1[X][Y] = '0';
ans += dis[x][y] + 1;
// cout << X << " " << Y << endl;
return ;
}
vis[xx][yy] = 1;
dis[xx][yy] = dis[x][y] + 1;
qx.push(xx);
qy.push(yy);
}
}
}
return ;
}
signed main()
{
for(int i = 1; i <= 4; i ++)
for(int j = 1; j <= 4; j ++)
cin >> mp1[i][j];
for(int i = 1; i <= 4; i ++)
{
for(int j = 1; j <= 4; j ++)
{
cin >> mp2[i][j];
if(mp2[i][j] == '1') k ++;
}
}
int m = k;
while(m --)
{
int x = 0, y = 0;
for(int i = 1; i <= 4; i ++)
{
for(int j = 1; j <= 4; j ++)
{
if(mp2[i][j] == '1' && mp1[i][j] == '0' && x == 0 && y == 0) x = i, y = j;
// if(mp1[i][j] == '1' && mp2[i][j] == '1') vis[i][j] = 1;
vis[i][j] = 0;
dis[i][j] = 0;
}
}
bfs(x, y);
}
cout << ans << endl;
return 0;
}
/*
1101
1111
1101
1011
1111
1101
0111
0111
*/
正解和第一种差不多,一开始是直接选最小的,实际上应该直接枚举两个谁和谁搭配,因为图很小,所以我们不用担心复杂度太高,我们可以把一开始就有的直接过滤掉。
#include<bits/stdc++.h>
#define int long long
#define N 10
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
int k,ans = N, cnt, cnt1, a[N][N], b[N][N], vis[N * N];
struct sb{int x, y;}s1[N * N], s2[N * N];
inline int js(int x,int y,int xx,int yy) {return abs(xx - x) + abs(yy - y);}
inline void DFS(int now,int tmp)
{
if(tmp > ans) return ;//已经劣于当前答案就直接退出
if(now == cnt1 + 1) return ans = min(ans, tmp), void();//搜完了取最小值
for(int i = 1;i <= cnt; i ++)//枚举每一个点
{
if(vis[i]) continue ;//已经有匹配的就退出
vis[i] = 1;//否则标记
int k = js(s2[now].x, s2[now].y, s1[i].x, s1[i].y);//计算曼哈顿距离
DFS(now + 1, tmp + k);//搜下一个
vis[i] = 0;//删标记
}
}
signed main()
{
for(int i = 1; i <= 4; i ++)
{
for(int j = 1; j <= 4; j ++)
{
char s; cin >> s; a[i][j] = s - '0';
if(a[i][j] == 1) s1[++ cnt].x = i, s1[cnt].y = j;
}
}
for(int i = 1; i <= 4; i ++)
{
for(int j = 1; j <= 4; j ++)
{
char s; cin >> s; b[i][j] = s - '0';
if(b[i][j] == 1) s2[++ cnt1].x = i, s2[cnt1].y = j;
}
}
DFS(1, 0);
cout << ans << endl;
return 0;
}
T2
二分 + 最小生成树。
我们发现最小联通的条件就是n-1条边可以走,那么我们直接二分加的倍数,然后sort一遍跑最小生成树,最后我们得到的就是当前的最小花费,如果要是小于x就不行,需要再加,反之则可以减少。
#include <bits/stdc++.h>
#define int long long
#define N 1000100
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
int n, m, X, fa[N];
struct sb{int u, v, a, b, w;} e[N];
inline int cmp(sb a, sb b) {return a.w < b.w;}
inline int fid(int x)
{
if(fa[x] == x) return x;
return fa[x] = fid(fa[x]);
}
inline int check(int x)
{
int num = 0, res = 0;
for(int i = 1; i <= n; i ++) fa[i] = i;
for(int i = 1; i <= m; i ++)
e[i].w = e[i].a + e[i].b * x;
sort(e + 1, e + m + 1, cmp);
for(int i = 1; i <= m; i ++)
{
int xx = fid(e[i].u);
int yy = fid(e[i].v);
if(xx == yy) continue;
res += e[i].w;
fa[xx] = yy;
num ++;
if(num == n - 1) break;
}
if(res > X) return 1;
else return 0;
}
signed main()
{
// freopen("ex_trap.in", "r", stdin);
n = read(), m = read(), X = read();
for(int i = 1; i <= m; i ++)
e[i] = {read(), read(), read(), read(), 0};
int l = 0, r = X / n + 1;
if(n > 1) r = X / (n - 1) + 1;
while(l < r)
{
int mid = (l + r) >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
// cout << mid << endl;
}
cout << l << endl;
return 0;
}
T3
建立最短路 DAG,假如存在一个点只有一个前驱,那么显然题目条件不可能满足。
假如所有点都有至少两个前驱,那么一定可以,我们可以通过构造证明:
取两条 \(1\) 到 \(i\) 的最短路,假设两条最短路除了 \(i\) 之外最后的交点为 \(k\),令第一条路线中 \(k\) 的后继是 \(j\),假如 \(j\) 存在的另一个前驱为 \(l\),把第一条路线换成 \(1\) 到 \(l\) 的最短路再接上第一条路线本来 \(j\) 到 \(i\) 的路线。发现这样替换后,两个路线的最后交点会越来越提前,直到为 \(1\) 即可。
#include <bits/stdc++.h>
#define pii pair<int, int>
#define int long long
#define N 300100
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
int n, m;
int g[N], in[N], dis[N];//g标记四不是合法
vector<pii> e[N];//存图
bitset<N> vis;//标记
priority_queue<pii, vector<pii>, greater<pii> > q;
inline void dij(int s)
{
for(int i = 1; i <= n; i ++) dis[i] = 1e18;//赋初值
dis[s] = 0;
g[s] = 1;//当前点是合法的
for(auto it : e[s])//遍历每一个边
{
int v = it.first;
g[v] = 1;//一开始直接和1相连的边是合法的
}
q.push({0, s});//入列
while (!q.empty())
{
int u = q.top().second;
q.pop();
if(vis[u]) continue ;
if(in[u] >= 2) g[u] = 1;//如果要是当前点合法的前驱有两个就标记合法
vis[u] = 1;
for(auto it : e[u])//枚举边
{
int v = it.first;
int w = it.second;
if (dis[u] + w < dis[v])
{
dis[v] = dis[u] + w;
in[v] = 0;
in[v] += g[u];//累加合法的前驱
q.push({dis[v], v});
}
else if(dis[u] + w == dis[v])//如果要是有相等的
in[v] += g[u];//累加当前点的前驱
}
}
}
signed main()
{
n = read(), m = read();
for(int i = 1; i <= m; i ++)
{
int x = read(), y = read(), w = read();
e[x].push_back({y, w});//存图
e[y].push_back({x, w});
}
dij(1);
for(int i = 2; i <= n; i ++)
{
if(in[i] >= 2) g[i] = 1;//如果大于等于2就合法
if(!g[i]) return puts("NO"), 0;//如果有不是合法的就直接退出
}
puts("YES");
return 0;
}
T4
考试的时候想到了dinic,但是没想到怎么维护最大值,最后的那个最大匹配是求出来了,但是最大值卡住了。
#include <bits/stdc++.h>
#define int long long
#define N 1001000
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
int n, m, ans, ans1, cnt, mi[N], a[N], head[N], cao[N];
struct sb{int u, v, next;} e[N];
inline void add(int u, int v)
{
e[++ cnt].u = u;
e[cnt].v = v;
e[cnt].next = head[u];
head[u] = cnt;
return ;
}
inline int DFS(int x)
{
for(int i = head[x]; i; i = e[i].next)
{
int v = e[i].v;
if(a[v]) continue;
a[v] = 1;
if(! mi[v] || DFS(mi[v]))
{
mi[v] = x;
return 1;
}
}
return 0;
}
inline void dinic()
{
for(int i = 1; i <= m; i ++)
{
memset(a, 0, sizeof a);
if(DFS(i)) ans1 ++;
}
return ;
}
signed main()
{
n = read(), m = read();
for(int i = 1; i <= m; i ++)
{
int l = read(), r = read(); cao[i] = read();
for(int j = l; j <= r; j ++)
add(i, m + j);
}
dinic();
for(int i = m + 1; i <= n + m; i ++)
{
if(mi[i] != 0)
ans += cao[mi[i] - n];
}
cout << ans1 << " " << ans << endl;
return 0;
}
STD:
#include <bits/stdc++.h>
using namespace std;
int read(){
int t=0;
static char ch;
while(ch=getchar(),ch<'0'||ch>'9');
t=ch^48;
while(ch=getchar(),ch>='0'&&ch<='9') t=t*10+(ch^48);
return t;
}
int n,m,ans,k,pv[510],qv[510],pre[510];
int vis[510];
struct nd{
int l,r,w;
}c[1000010];
void build(){
queue<int>q;
for(int i=0;i<m;i++) vis[i]=0,pre[i]=-1;
for(int i=0;i<m;i++) if(!~pv[i]) q.push(i),vis[i]=1;
while(q.size()){
int u=q.front();q.pop();
for(int j=0;j<k;j++) if(c[j].l<=u&&c[j].r>=u&&!vis[qv[j]]){
q.push(qv[j]),vis[qv[j]]=1,pre[qv[j]]=u;
}
}
for(int i=1;i<m;i++) vis[i]+=vis[i-1];
}
void work(int l,int r,int w){
int tp=vis[r]-(l?vis[l-1]:0);
if(!tp) return;
c[k++]={l,r,w},ans+=w;
int u=0,v=k-1;
for(int i=l;i<=r;i++) if(vis[i]-(i?vis[i-1]:0)){
u=i;
break;
}
do{
int tp=pv[u];
pv[u]=v,qv[v]=u,u=pre[u],v=tp;
}while(~v);
build();
}
int main(){
m=read(),n=read();
for(int i=0;i<n;i++) c[i].l=read(),c[i].r=read(),c[i].w=read(),c[i].l--,c[i].r--;
sort(c,c+n,[](nd a,nd b){return a.w>b.w;});
for(int i=0;i<m;i++) pv[i]=qv[i]=-1;
ans=k=0;
build();
for(int i=0;i<n;i++) work(c[i].l,c[i].r,c[i].w);
printf("%d %d\n",k,ans);
}
.
本文来自博客园,作者:北烛青澜,转载请注明原文链接:https://www.cnblogs.com/Multitree/articles/17583693.html
The heart is higher than the sky, and life is thinner than paper.
浙公网安备 33010602011771号