FloydWarshall
Gamble1
ModifiedDijkstra
OptimizedBellmanFord
RecursiveBacktracking
题目:http://uoj.ac/problem/109
思路:第一次做提交答案题,做了整整一天
其主要难点在于
subtask4,6
,其他的都很快解决。
subtask1
:
注意到
FloydWarshall
的运行只依赖于点的个数,而
ModifiedDijkstra
并不是如此,我们直接构造一张
V=101
的空图就好了。
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
int n;
int main(){
freopen("task1.in","w",stdout);
n = 101;
cout<<n<<endl;
for (int i = 1;i <= n; ++i) puts("0");
cout<<1<<endl;
cout<<1<<" "<<1<<endl;
fclose(stdout);
return 0;
}
subtask2
:
注意到
OptimizedBellmanFord
的最坏复杂度是
O(VE)
,我们想让它达到这个复杂度,必须每次松弛的每个点都被更新,而且每次单点的值都被更新,也就是说每次只有一个点达到
mindist
,这样的话注意到循环顺序是
0
到
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
int n,num;
int main(){
freopen("task2.in","w",stdout);
n = 100;
num = 0;
cout<<n<<endl;
cout<<0<<endl;
cout<<70<<" "<<0<<" "<<0<<" ";
for (int i = 1;i <= 69; ++i) cout<<0<<" "<<1<<" ",num += 2;
cout<<endl;
for (int i = 2;i < n; ++i)
{ cout<<10<<" "<<i - 1<<" "<<0<<" ";
num += 3;
for (int j = 1;j <= 9; ++j) cout<<i - 1<<" "<<1<<" ",num += 2;
cout<<endl;
}
cout<<10<<endl;
for (int i = 1;i <= 10; ++i) cout<<n - 1<<" "<<0<<endl,num += 2;
cout<<num + 6<<endl;
fclose(stdout);
return 0;
}
subtask3
:
和
subtask1
一样,还是卡点数
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
int n;
int main(){
freopen("task3.in","w",stdout);
n = 101;
cout<<n<<endl;
for (int i = 1;i <= n; ++i) cout<<0<<endl;
cout<<1<<endl;
cout<<1<<" "<<1;
fclose(stdout);
return 0;
}
subtask4,6
这两个点是可以一起搞的,构造思路比较新颖,卡了我好久。
考虑
ModifiedDijkstra
的复杂度是依赖于没有负边的,又注意到我们想让一个点不断被更新,那么根据松弛原理,我们连
(0,1,1)(0,2,2)(2,1,−2)
这样的基本图形会导致
2
被更新两遍,于是我们暴力的把这样的基本图形串起来,对于这个图形如果想要得到指数数量级的话必须有限制,我们把它想象成一个实现的堆栈,不断上下递归,那么对于
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;
int V,E,n,num,sum,d,f[100];
int main(){
//freopen("task4.in","w",stdout);
n = 16;
num = 0;
V = 2 * n + 1;
cout<<V<<endl;
f[n - 1] = -2; sum = -2;
d = 2;
for (int i = n - 2;i >= 0; --i){
f[i] = sum * d;
sum += f[i];
if (i == 0) f[i] = -999999;
if (sum < -10000) sum += 5000;
else
if (sum < -2500) sum += 1250;
else
if (sum < -50) sum += 25;
}
for (int i = 0;i < n; ++i){
cout<<2<<" "<<2 * i + 2<<" "<<-2<<" "<<2 * i + 1<<" "<<-1<<endl;
num +=5;
if (i != n - 1) cout<<1<<" "<<2 * i + 2<<" "<<f[i]<<endl,num += 3;
else cout<<0<<endl,num += 1;
}
cout<<0<<endl;
cout<<7<<endl;
for (int i = 1;i <= 7; ++i) cout<<0<<" "<<V - 1<<" "<<endl,num += 2;
cout<<num + 3<<endl;
fclose(stdout);
}
subtask5
:
我们只需要修改
subtask2
,各种尝试限制边的个数,注意到在这里
V
越大效果越好。
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
int n,num;
int main(){
freopen("task5.in","w",stdout);
num = 0;
n = 290;
cout<<n<<endl;
cout<<0<<endl;
for (int i = 1;i < n; ++i)
{ if (i > 230) cout<<2<<" "<<i - 1<<" "<<0<<" ";
else cout<<1<<" "<<i - 1<<" "<<0<<" ";
num += 3;
if (i > 230) for (int j = 1;j <= 1; ++j) cout<<i - 1<<" "<<1<<" ",num += 2;
cout<<endl;
}
cout<<10<<endl;
for (int i = 1;i <= 10; ++i) cout<<n - 1<<" "<<0<<endl;
//cout<<num + 23<<endl;
fclose(stdout);
return 0;
}
为了让暴搜非常慢我们可以尽可能的构造一张大的完全图,这样就能过了。
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
int V,E,num;
int main(){
freopen("task7.in","w",stdout);
V = 999; E = 1501;
num = 0;
cout<<V<<" "<<E<<endl;
for (int i = 0;i <= 54; ++i)
for (int j = 0;j < i; ++j)
cout<<i<<" "<<j<<endl,num+=2;
for (int i = 1;i <= 16; ++i) cout<<V - i<<" "<<V - i - 1<<endl,num += 2;
//cout<<num + 2;
fclose(stdout);
return 0;
}
subtask8
:
8和9都是染色问题,要求相邻的颜色不相同,给出了一个暴搜程序。
为了让它过掉又尽可能边数满足条件,这样构造:
构造
249
个点数为
4
的完全图,然后剩下
最后将三个点每个点向其中一个四个点的完全图连边,要求各不相同且有一个3-完全图点连了
2
<script type="math/tex" id="MathJax-Element-33">2</script>个4-完全图的点。
代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
int V,E,num;
int main(){
freopen("task8.in","w",stdout);
V = 999; E = 1501;
cout<<V<<" "<<E<<endl;
num = 0;
for (int i = 0;i < V - 3; ++i){
if (i % 4 == 1) cout<<i<<" "<<i - 1<<endl,num += 2;
if (i % 4 == 2) cout<<i<<" "<<i - 1<<endl<<i<<" "<<i - 2<<endl,num += 4;
if (i % 4 == 3) cout<<i<<" "<<i - 1<<endl<<i<<" "<<i - 2<<endl<<i<<" "<<i - 3<<endl,num += 6;
}
cout<<V - 1<<" "<<V - 2<<endl<<V - 1<<" "<<V - 3<<endl<<V - 2<<" "<<V - 3<<endl;
cout<<V - 1<<" "<<V - 4<<endl<<V - 2<<" "<<V - 5<<endl<<V - 3<<" "<<V - 6<<endl<<V - 1<<" "<<V - 7<<endl;
fclose(stdout);
return 0;
}