目录
[1.P3853 [TJOI2007] 路标设置](#1.P3853 [TJOI2007] 路标设置)
[2.P1129 [ZJOI2007] 矩阵游戏](#2.P1129 [ZJOI2007] 矩阵游戏)
[3.P1330 封锁阳光大学](#3.P1330 封锁阳光大学)
[5.P1141 01迷宫](#5.P1141 01迷宫)
1.P3853 [TJOI2007] 路标设置
P3853 [TJOI2007] 路标设置 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
先求出每个路标之间的距离,再二分查找每个mid,如果有间距大于mid的,那我们就设立路标,到最后,看新设置的路标数量是否在要求的范围之内。
cpp
#include<iostream>
#include<algorithm>
#include<queue>
#include<math.h>
#include<cstring>
#include<map>
#define ll long long
#define TEST int T;cin>>T;while(T--)
#define lowbit(x) x&(-x)
using namespace std;
const int N = 2000100;
const int M = 1e8 + 7;
int base1 = 131, base2 = 13311;
ll w, n, k;
ll a[N];
bool check(ll x) {
ll ans = 0;
for (int i = 1; i < n; i++) {
if(a[i]>x)
{
ans+=(a[i]-1)/x;
}
}
return ans<=k;
}
void solve() {
cin >> w >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n - 1; i++) a[i] = a[i + 1] - a[i];
ll L = 1, R = w, mid;
while (L < R) {
mid = L + R >> 1;
if (check(mid)) {
R = mid ;
} else L = mid+1;
}
cout << R << "\n";
}
int main() {
solve();
return 0;
}
2.P1129 [ZJOI2007] 矩阵游戏
P1129 [ZJOI2007] 矩阵游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
其实就是二部图的最大匹配,在我们给出的矩阵中,我们给(i,j)建边,当找到的最大匹配大于等于n时,那就说明可以组成一条主对角线的元素都为1。
我们这里用到匈牙利算法。
cpp
#include<iostream>
#include<algorithm>
#include<queue>
#include<math.h>
#include<cstring>
#include<map>
#define ll long long
#define TEST int T;cin>>T;while(T--)
#define lowbit(x) x&(-x)
using namespace std;
const int N = 100010;
const int M = 200010;
int base1 = 131, base2 = 13311;
ll n, m, head[N], cnt, colour[N], match[N], v[N];
struct Node {
int u, v;
} e[N];
void add(int u, int v) { //链式前向星存图
e[++cnt].u = v;
e[cnt].v = head[u];
head[u] = cnt;
}
void bak()
{
for(int i=0;i<=n;i++)
{
e[i].u=e[i].v=v[i]=match[i]=head[i]=0;
}
cnt=0;
}
bool dfs(int p,int tag)
{
if(v[p]==tag) return false;
v[p]=tag;
for(int i=head[p];i;i=e[i].v)
{
int pos=e[i].u;
if(!match[pos]||dfs(match[pos],tag))
{
match[pos]=p;
return true;
}
}
return false;
}
void solve() {
cin>>n;
for (int i = 1, x; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> x;
if (x) add(i, j );
}
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
if (dfs(i,i)) ans++;
}
if (ans >= n) cout << "Yes\n";
else cout << "No\n";
bak();
}
int main() {
TEST
solve();
return 0;
}
3.P1330 封锁阳光大学
P1330 封锁阳光大学 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
首先判断是否构成二分图,用染色法每次遍历的时候,答案累加上此时染成两个集合中元素的最小值。
最后输出答案。
cpp
#include<iostream>
#include<algorithm>
#include<queue>
#include<math.h>
#include<cstring>
#include<map>
#define ll long long
#define TEST int T;cin>>T;while(T--)
#define lowbit(x) x&(-x)
using namespace std;
const int N = 100010;
const int M = 200010;
int base1 = 131, base2 = 13311;
ll n, m, head[N], cnt, colour[N], match[N], v[N], Ans[4];
struct Node {
int u, v;
} e[N];
void add(int u, int v) { //链式前向星存图
e[++cnt].u = v;
e[cnt].v = head[u];
head[u] = cnt;
}
bool find1(int x, int tag) {
colour[x] = tag;
Ans[tag]++;
for (int i = head[x]; i; i = e[i].v) {
int pos = e[i].u;
if (!colour[pos]) {
if (!find1(pos, 3 - tag)) return false;
} else {
if (colour[pos] == tag) return false;
}
}
return true;
}
void solve() {
cin >> n >> m;
for (int u, v; m; m--) {
cin >> u >> v;
add(u, v);
add(v, u);
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
Ans[1] = 0, Ans[2] = 0;
if (!colour[i]) {
if (!find1(i, 1)) {
cout << "Impossible\n";
return;
}
}
ans += min(Ans[2], Ans[1]);
}
cout << ans << "\n";
}
int main() {
solve();
return 0;
}
4.Trees
先将每个起点和终点排序,安装具体情况更新L和R,最后答案减去(R-L+1)。
cpp
#include<iostream>
#include<algorithm>
#include<queue>
#include<math.h>
#include<cstring>
#include<map>
#define ll long long
#define TEST int T;cin>>T;while(T--)
#define lowbit(x) x&(-x)
using namespace std;
const int N = 5010;
const int M = 200010;
int base1 = 131, base2 = 13311;
ll n, m, head[N], cnt, colour[N], match[N], v[N];
struct Node {
ll u, v;
} e[N];
bool cmp(Node a, Node b) {
if (a.u == b.u) return a.v < b.v;
return a.u < b.u;
}
void solve() {
while (cin >> n >> m) {
if(n==m&&n==0) break;
for (int i = 1; i <= m; i++) {
cin >> e[i].u >> e[i].v;
if (e[i].u > e[i].v) swap(e[i].u, e[i].v);
}
sort(e + 1, e + 1 + m, cmp);
ll ans = n + 1;
ll L = e[1].u, R = e[1].v;
for (int i = 2; i <= m; i++) {
if (e[i].u <= R) {
R = e[i].v;
continue;
}
if (e[i].u > R) {
ans -= (R - L + 1);
L = e[i].u;
R = e[i].v;
continue;
}
}
cout << (ans - R + L - 1) << "\n";
}
}
int main() {
solve();
return 0;
}
5.P1141 01迷宫
P1141 01迷宫 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
我们知道,就是寻找按照要求的联通块,我们可以用dfs遍历,这样询问时,只需要找到这个位置在哪个联通块里面,每个联通块的权重就是联通块内元素的数量。
cpp
#include<iostream>
#include<algorithm>
#include<queue>
#include<math.h>
#include<cstring>
#include<map>
#define ll long long
#define TEST int T;cin>>T;while(T--)
#define lowbit(x) x&(-x)
using namespace std;
const int N = 2000100;
const int M = 1e8 + 7;
int base1 = 131, base2 = 13311;
char mp[1001][1001];
int ans[1001][1001];
int dx[]={1,-1,0,0};
int dy[]={0,0,1,-1};
map<ll,ll>f;
int cnt=0;
ll n,m;
void dfs(int x,int y,char tag)
{
if(x<1||y<1||x>n||y>n) return;
ans[x][y]=cnt;
f[cnt]++;
for(int i=0;i<4;i++)
{
int tx=x+dx[i];
int ty=y+dy[i];
if(!ans[tx][ty]&&mp[tx][ty]=='1'-mp[x][y]+'0')
{
dfs(tx,ty,'1'-mp[x][y]+'0');
}
}
}
void solve() {
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>mp[i][j];
}
}
for(int i=1,x,y;i<=m;i++)
{
cin>>x>>y;
if(ans[x][y]) cout<<f[ans[x][y]]<<"\n";
else cnt++,dfs(x,y,mp[x][y]),cout<<f[cnt]<<"\n";
}
}
int main() {
solve();
return 0;
}